Merge branch 'master' of ../../drm into modesetting-101
authorDave Airlie <airlied@redhat.com>
Fri, 7 Mar 2008 00:59:21 +0000 (11:59 +1100)
committerDave Airlie <airlied@redhat.com>
Fri, 7 Mar 2008 00:59:21 +0000 (11:59 +1100)
121 files changed:
libdrm/Makefile.am
libdrm/xf86drm.c
libdrm/xf86drm.h
libdrm/xf86drmMode.c [new file with mode: 0644]
libdrm/xf86drmMode.h [new file with mode: 0644]
linux-core/Makefile
linux-core/Makefile.kernel
linux-core/drmP.h
linux-core/drm_auth.c
linux-core/drm_bo.c
linux-core/drm_bo_move.c
linux-core/drm_bufs.c
linux-core/drm_compat.c
linux-core/drm_compat.h
linux-core/drm_context.c
linux-core/drm_crtc.c [new file with mode: 0644]
linux-core/drm_crtc.h [new file with mode: 0644]
linux-core/drm_drv.c
linux-core/drm_edid.c [new file with mode: 0644]
linux-core/drm_edid.h [new file with mode: 0644]
linux-core/drm_fb.c [new file with mode: 0644]
linux-core/drm_fops.c
linux-core/drm_ioctl.c
linux-core/drm_irq.c
linux-core/drm_lock.c
linux-core/drm_mm.c
linux-core/drm_modes.c [new file with mode: 0644]
linux-core/drm_objects.h
linux-core/drm_proc.c
linux-core/drm_stub.c
linux-core/drm_sysfs.c
linux-core/i915_buffer.c
linux-core/i915_drv.c
linux-core/i915_fence.c
linux-core/i915_init.c [new symlink]
linux-core/intel_crt.c [new file with mode: 0644]
linux-core/intel_display.c [new file with mode: 0644]
linux-core/intel_drv.h [new file with mode: 0644]
linux-core/intel_fb.c [new file with mode: 0644]
linux-core/intel_i2c.c [new file with mode: 0644]
linux-core/intel_lvds.c [new file with mode: 0644]
linux-core/intel_modes.c [new file with mode: 0644]
linux-core/intel_sdvo.c [new file with mode: 0644]
linux-core/intel_sdvo_regs.h [new file with mode: 0644]
linux-core/intel_tv.c [new file with mode: 0644]
linux-core/radeon_ms.h [new symlink]
linux-core/radeon_ms_bo.c [new symlink]
linux-core/radeon_ms_bus.c [new symlink]
linux-core/radeon_ms_combios.c [new symlink]
linux-core/radeon_ms_combios.h [new symlink]
linux-core/radeon_ms_compat.c [new file with mode: 0644]
linux-core/radeon_ms_cp.c [new symlink]
linux-core/radeon_ms_cp_mc.c [new symlink]
linux-core/radeon_ms_crtc.c [new symlink]
linux-core/radeon_ms_dac.c [new symlink]
linux-core/radeon_ms_drm.c [new symlink]
linux-core/radeon_ms_drm.h [new symlink]
linux-core/radeon_ms_drv.c [new file with mode: 0644]
linux-core/radeon_ms_drv.h [new file with mode: 0644]
linux-core/radeon_ms_exec.c [new symlink]
linux-core/radeon_ms_family.c [new symlink]
linux-core/radeon_ms_fb.c [new file with mode: 0644]
linux-core/radeon_ms_fence.c [new symlink]
linux-core/radeon_ms_gpu.c [new symlink]
linux-core/radeon_ms_i2c.c [new symlink]
linux-core/radeon_ms_irq.c [new symlink]
linux-core/radeon_ms_output.c [new symlink]
linux-core/radeon_ms_properties.c [new symlink]
linux-core/radeon_ms_properties.h [new symlink]
linux-core/radeon_ms_reg.h [new symlink]
linux-core/radeon_ms_rom.c [new symlink]
linux-core/radeon_ms_rom.h [new symlink]
linux-core/radeon_ms_state.c [new symlink]
linux-core/via_fence.c
shared-core/drm.h
shared-core/drm_pciids.txt
shared-core/i915_dma.c
shared-core/i915_drm.h
shared-core/i915_drv.h
shared-core/i915_init.c [new file with mode: 0644]
shared-core/i915_irq.c
shared-core/i915_mem.c
shared-core/radeon_drm.h
shared-core/radeon_ms.h [new file with mode: 0644]
shared-core/radeon_ms_bo.c [new file with mode: 0644]
shared-core/radeon_ms_bus.c [new file with mode: 0644]
shared-core/radeon_ms_combios.c [new file with mode: 0644]
shared-core/radeon_ms_combios.h [new file with mode: 0644]
shared-core/radeon_ms_cp.c [new file with mode: 0644]
shared-core/radeon_ms_cp_mc.c [new file with mode: 0644]
shared-core/radeon_ms_crtc.c [new file with mode: 0644]
shared-core/radeon_ms_dac.c [new file with mode: 0644]
shared-core/radeon_ms_drm.c [new file with mode: 0644]
shared-core/radeon_ms_drm.h [new file with mode: 0644]
shared-core/radeon_ms_exec.c [new file with mode: 0644]
shared-core/radeon_ms_family.c [new file with mode: 0644]
shared-core/radeon_ms_fence.c [new file with mode: 0644]
shared-core/radeon_ms_gpu.c [new file with mode: 0644]
shared-core/radeon_ms_i2c.c [new file with mode: 0644]
shared-core/radeon_ms_irq.c [new file with mode: 0644]
shared-core/radeon_ms_output.c [new file with mode: 0644]
shared-core/radeon_ms_properties.c [new file with mode: 0644]
shared-core/radeon_ms_properties.h [new file with mode: 0644]
shared-core/radeon_ms_reg.h [new file with mode: 0644]
shared-core/radeon_ms_rom.c [new file with mode: 0644]
shared-core/radeon_ms_rom.h [new file with mode: 0644]
shared-core/radeon_ms_state.c [new file with mode: 0644]
shared-core/radeon_state.c
tests/dristat.c
tests/mode/Makefile [new file with mode: 0644]
tests/mode/modetest.c [new file with mode: 0644]
tests/mode/test [new file with mode: 0755]
tests/modedemo/Makefile [new file with mode: 0644]
tests/modedemo/demo.c [new file with mode: 0644]
tests/modedemo/test [new file with mode: 0755]
tests/modefb/Makefile [new file with mode: 0644]
tests/modefb/demo.c [new file with mode: 0644]
tests/modefb/test [new file with mode: 0755]
tests/modehotplug/Makefile [new file with mode: 0644]
tests/modehotplug/demo.c [new file with mode: 0644]
tests/modehotplug/test [new file with mode: 0755]

index e7e07e4..24c3203 100644 (file)
@@ -23,9 +23,9 @@ libdrm_ladir = $(libdir)
 libdrm_la_LDFLAGS = -version-number 2:3:0 -no-undefined
 
 AM_CFLAGS = -I$(top_srcdir)/shared-core
-libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c
+libdrm_la_SOURCES = xf86drm.c xf86drmHash.c xf86drmRandom.c xf86drmSL.c xf86drmMode.c
 
 libdrmincludedir = ${includedir}
-libdrminclude_HEADERS = xf86drm.h xf86mm.h
+libdrminclude_HEADERS = xf86drm.h xf86mm.h xf86drmMode.h
 
 EXTRA_DIST = ChangeLog TODO
index 3317ba5..bcf562d 100644 (file)
@@ -87,6 +87,9 @@
 
 #define DRM_MSG_VERBOSITY 3
 
+#define DRM_NODE_CONTROL 0
+#define DRM_NODE_RENDER 1
+
 static drmServerInfoPtr drm_server_info;
 
 void drmSetServerInfo(drmServerInfoPtr info)
@@ -264,7 +267,7 @@ static int drmMatchBusID(const char *id1, const char *id2)
  * special file node with the major and minor numbers specified by \p dev and
  * parent directory if necessary and was called by root.
  */
-static int drmOpenDevice(long dev, int minor)
+static int drmOpenDevice(long dev, int minor, int type)
 {
     stat_t          st;
     char            buf[64];
@@ -274,7 +277,7 @@ static int drmOpenDevice(long dev, int minor)
     uid_t           user    = DRM_DEV_UID;
     gid_t           group   = DRM_DEV_GID, serv_group;
     
-    sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor);
+    sprintf(buf, type ? DRM_DEV_NAME : DRM_CONTROL_DEV_NAME, DRM_DIR_NAME, minor);
     drmMsg("drmOpenDevice: node name is %s\n", buf);
 
     if (drm_server_info) {
@@ -348,15 +351,15 @@ static int drmOpenDevice(long dev, int minor)
  * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
  * name from \p minor and opens it.
  */
-static int drmOpenMinor(int minor, int create)
+static int drmOpenMinor(int minor, int create, int type)
 {
     int  fd;
     char buf[64];
     
     if (create)
-       return drmOpenDevice(makedev(DRM_MAJOR, minor), minor);
+      return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
     
-    sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, minor);
+    sprintf(buf, type ? DRM_DEV_NAME : DRM_CONTROL_DEV_NAME, DRM_DIR_NAME, minor);
     if ((fd = open(buf, O_RDWR, 0)) >= 0)
        return fd;
     return -errno;
@@ -379,7 +382,7 @@ int drmAvailable(void)
     int           retval = 0;
     int           fd;
 
-    if ((fd = drmOpenMinor(0, 1)) < 0) {
+    if ((fd = drmOpenMinor(0, 1, DRM_NODE_RENDER)) < 0) {
 #ifdef __linux__
        /* Try proc for backward Linux compatibility */
        if (!access("/proc/dri/0", R_OK))
@@ -420,7 +423,7 @@ static int drmOpenByBusid(const char *busid)
 
     drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
     for (i = 0; i < DRM_MAX_MINOR; i++) {
-       fd = drmOpenMinor(i, 1);
+       fd = drmOpenMinor(i, 1, DRM_NODE_RENDER);
        drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
        if (fd >= 0) {
            sv.drm_di_major = 1;
@@ -482,7 +485,7 @@ static int drmOpenByName(const char *name)
      * already in use.  If it's in use it will have a busid assigned already.
      */
     for (i = 0; i < DRM_MAX_MINOR; i++) {
-       if ((fd = drmOpenMinor(i, 1)) >= 0) {
+       if ((fd = drmOpenMinor(i, 1, DRM_NODE_RENDER)) >= 0) {
            if ((version = drmGetVersion(fd))) {
                if (!strcmp(version->name, name)) {
                    drmFreeVersion(version);
@@ -526,7 +529,7 @@ static int drmOpenByName(const char *name)
                        if (*pt) { /* Found busid */
                            return drmOpenByBusid(++pt);
                        } else { /* No busid */
-                           return drmOpenDevice(strtol(devstring, NULL, 0),i);
+                           return drmOpenDevice(strtol(devstring, NULL, 0),i, DRM_NODE_RENDER);
                        }
                    }
                }
@@ -576,6 +579,10 @@ int drmOpen(const char *name, const char *busid)
     return -1;
 }
 
+int drmOpenControl(int minor)
+{
+    return drmOpenMinor(minor, 0, DRM_NODE_CONTROL);
+}
 
 /**
  * Free the version information returned by drmGetVersion().
index 230f54c..7b41860 100644 (file)
@@ -49,6 +49,7 @@
 
 #define DRM_DIR_NAME  "/dev/dri"
 #define DRM_DEV_NAME  "%s/card%d"
+#define DRM_CONTROL_DEV_NAME  "%s/controlD%d"
 #define DRM_PROC_NAME "/proc/dri/" /* For backward Linux compatibility */
 
 #define DRM_ERR_NO_DEVICE  (-1001)
@@ -508,6 +509,7 @@ do {        register unsigned int __old __asm("o0");                \
 /* General user-level programmer's API: unprivileged */
 extern int           drmAvailable(void);
 extern int           drmOpen(const char *name, const char *busid);
+extern int drmOpenControl(int minor);
 extern int           drmClose(int fd);
 extern drmVersionPtr drmGetVersion(int fd);
 extern drmVersionPtr drmGetLibVersion(int fd);
diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c
new file mode 100644 (file)
index 0000000..f86cc48
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * \file xf86drmMode.c
+ * Header for DRM modesetting interface.
+ *
+ * \author Jakob Bornecrantz <wallbraker@gmail.com>
+ *
+ * \par Acknowledgements:
+ * Feb 2007, Dave Airlie <airlied@linux.ie>
+ */
+
+/*
+ * Copyright (c) <year> <copyright holders>
+ *
+ * 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
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ */
+
+/*
+ * TODO the types we are after are defined in diffrent headers on diffrent
+ * platforms find which headers to include to get uint32_t
+ */
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+
+#include "xf86drmMode.h"
+#include "xf86drm.h"
+#include <drm.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+
+#define U642VOID(x) ((void *)(unsigned long)(x))
+#define VOID2U64(x) ((uint64_t)(unsigned long)(x))
+
+/*
+ * Util functions
+ */
+
+void* drmAllocCpy(void *array, int count, int entry_size)
+{
+       char *r;
+       int i;
+
+       if (!count || !array || !entry_size)
+               return 0;
+
+       if (!(r = drmMalloc(count*entry_size)))
+               return 0;
+
+       for (i = 0; i < count; i++)
+               memcpy(r+(entry_size*i), array+(entry_size*i), entry_size);
+
+       return r;
+}
+
+/*
+ * A couple of free functions.
+ */
+
+void drmModeFreeModeInfo(struct drm_mode_modeinfo *ptr)
+{
+       if (!ptr)
+               return;
+
+       drmFree(ptr);
+}
+
+void drmModeFreeResources(drmModeResPtr ptr)
+{
+       if (!ptr)
+               return;
+
+       drmFree(ptr);
+
+}
+
+void drmModeFreeFB(drmModeFBPtr ptr)
+{
+       if (!ptr)
+               return;
+
+       /* we might add more frees later. */
+       drmFree(ptr);
+}
+
+void drmModeFreeCrtc(drmModeCrtcPtr ptr)
+{
+       if (!ptr)
+               return;
+
+       drmFree(ptr);
+
+}
+
+void drmModeFreeOutput(drmModeOutputPtr ptr)
+{
+       if (!ptr)
+               return;
+
+       drmFree(ptr->modes);
+       drmFree(ptr);
+
+}
+
+/*
+ * ModeSetting functions.
+ */
+
+drmModeResPtr drmModeGetResources(int fd)
+{
+       struct drm_mode_card_res res;
+       drmModeResPtr r = 0;
+
+       memset(&res, 0, sizeof(struct drm_mode_card_res));
+
+       if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
+               return 0;
+
+       if (res.count_fbs)
+               res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t)));
+       if (res.count_crtcs)
+               res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t)));
+       if (res.count_outputs)
+               res.output_id_ptr = VOID2U64(drmMalloc(res.count_outputs*sizeof(uint32_t)));
+
+       if (ioctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) {
+               r = NULL;
+               goto err_allocs;
+       }
+
+       /*
+        * return
+        */
+
+
+       if (!(r = drmMalloc(sizeof(*r))))
+               return 0;
+
+       r->min_width     = res.min_width;
+       r->max_width     = res.max_width;
+       r->min_height    = res.min_height;
+       r->max_height    = res.max_height;
+       r->count_fbs     = res.count_fbs;
+       r->count_crtcs   = res.count_crtcs;
+       r->count_outputs = res.count_outputs;
+       /* TODO we realy should test if these allocs fails. */
+       r->fbs           = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t));
+       r->crtcs         = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t));
+       r->outputs       = drmAllocCpy(U642VOID(res.output_id_ptr), res.count_outputs, sizeof(uint32_t));
+
+err_allocs:
+       drmFree(U642VOID(res.fb_id_ptr));
+       drmFree(U642VOID(res.crtc_id_ptr));
+       drmFree(U642VOID(res.output_id_ptr));
+
+       return r;
+}
+
+uint32_t drmModeGetHotplug(int fd)
+{
+       struct drm_mode_hotplug arg;
+       arg.counter = 0;
+
+       ioctl(fd, DRM_IOCTL_MODE_HOTPLUG, &arg);
+       return arg.counter;
+}
+
+int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth,
+                 uint8_t bpp, uint32_t pitch, uint32_t bo_handle,
+                uint32_t *buf_id)
+{
+       struct drm_mode_fb_cmd f;
+       int ret;
+
+       f.width  = width;
+       f.height = height;
+       f.pitch  = pitch;
+       f.bpp    = bpp;
+       f.depth  = depth;
+       f.handle = bo_handle;
+
+       if ((ret = ioctl(fd, DRM_IOCTL_MODE_ADDFB, &f)))
+               return ret;
+
+       *buf_id = f.buffer_id;
+       return 0;
+}
+
+int drmModeRmFB(int fd, uint32_t bufferId)
+{
+       return ioctl(fd, DRM_IOCTL_MODE_RMFB, &bufferId);
+
+
+}
+
+drmModeFBPtr drmModeGetFB(int fd, uint32_t buf)
+{
+       struct drm_mode_fb_cmd info;
+       drmModeFBPtr r;
+
+       info.buffer_id = buf;
+
+       if (ioctl(fd, DRM_IOCTL_MODE_GETFB, &info))
+               return NULL;
+
+       if (!(r = drmMalloc(sizeof(*r))))
+               return NULL;
+
+       r->buffer_id = info.buffer_id;
+       r->width = info.width;
+       r->height = info.height;
+       r->pitch = info.pitch;
+       r->bpp = info.bpp;
+       r->handle = info.handle;
+       r->depth = info.depth;
+
+       return r;
+}
+
+
+/*
+ * Crtc functions
+ */
+
+drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId)
+{
+       struct drm_mode_crtc crtc;
+       drmModeCrtcPtr r;
+
+       crtc.count_outputs   = 0;
+       crtc.outputs         = 0;
+       crtc.count_possibles = 0;
+       crtc.possibles       = 0;
+       crtc.crtc_id = crtcId;
+
+       if (ioctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc))
+               return 0;
+
+       /*
+        * return
+        */
+
+       if (!(r = drmMalloc(sizeof(*r))))
+               return 0;
+       
+       r->crtc_id         = crtc.crtc_id;
+       r->x               = crtc.x;
+       r->y               = crtc.y;
+       r->mode_valid      = crtc.mode_valid;
+       if (r->mode_valid)
+               memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo));
+       r->buffer_id       = crtc.fb_id;
+       r->gamma_size      = crtc.gamma_size;
+       r->count_outputs   = crtc.count_outputs;
+       r->count_possibles = crtc.count_possibles;
+       /* TODO we realy should test if these alloc & cpy fails. */
+       r->outputs         = crtc.outputs;
+       r->possibles       = crtc.possibles;
+
+       return r;
+}
+
+
+int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
+                   uint32_t x, uint32_t y, uint32_t *outputs, int count,
+                  struct drm_mode_modeinfo *mode)
+{
+       struct drm_mode_crtc crtc;
+
+       crtc.count_outputs   = 0;
+       crtc.outputs         = 0;
+       crtc.count_possibles = 0;
+       crtc.possibles       = 0;
+
+       crtc.x             = x;
+       crtc.y             = y;
+       crtc.crtc_id       = crtcId;
+       crtc.fb_id         = bufferId;
+       crtc.set_outputs_ptr = VOID2U64(outputs);
+       crtc.count_outputs = count;
+       if (mode) {
+         memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo));
+         crtc.mode_valid = 1;
+       } else
+         crtc.mode_valid = 0;
+
+       return ioctl(fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
+}
+
+/*
+ * Cursor manipulation
+ */
+
+int drmModeSetCursor(int fd, uint32_t crtcId, drmBO *bo, uint32_t width, uint32_t height)
+{
+       struct drm_mode_cursor arg;
+
+       arg.flags = DRM_MODE_CURSOR_BO;
+       arg.crtc = crtcId;
+       arg.width = width;
+       arg.height = height;
+       if (bo)
+               arg.handle = bo->handle;
+       else
+               arg.handle = 0;
+
+       return ioctl(fd, DRM_IOCTL_MODE_CURSOR, &arg);
+}
+
+int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y)
+{
+       struct drm_mode_cursor arg;
+
+       arg.flags = DRM_MODE_CURSOR_MOVE;
+       arg.crtc = crtcId;
+       arg.x = x;
+       arg.y = y;
+
+       return ioctl(fd, DRM_IOCTL_MODE_CURSOR, &arg);
+}
+
+/*
+ * Output manipulation
+ */
+
+drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id)
+{
+       struct drm_mode_get_output out;
+       drmModeOutputPtr r = NULL;
+
+       out.output = output_id;
+       out.output_type_id = 0;
+       out.output_type  = 0;
+       out.count_crtcs  = 0;
+       out.crtcs        = 0;
+       out.count_clones = 0;
+       out.clones       = 0;
+       out.count_modes  = 0;
+       out.modes_ptr    = 0;
+       out.count_props  = 0;
+       out.props_ptr    = 0;
+       out.prop_values_ptr = 0;
+
+       if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out))
+               return 0;
+
+       if (out.count_props) {
+               out.props_ptr = VOID2U64(drmMalloc(out.count_props*sizeof(uint32_t)));
+               out.prop_values_ptr = VOID2U64(drmMalloc(out.count_props*sizeof(uint64_t)));
+       }
+
+       if (out.count_modes)
+               out.modes_ptr = VOID2U64(drmMalloc(out.count_modes*sizeof(struct drm_mode_modeinfo)));
+
+       if (ioctl(fd, DRM_IOCTL_MODE_GETOUTPUT, &out))
+               goto err_allocs;
+
+       if(!(r = drmMalloc(sizeof(*r)))) {
+               goto err_allocs;
+       }
+
+       r->output_id = out.output;
+       r->crtc = out.crtc;
+       r->connection   = out.connection;
+       r->mmWidth      = out.mm_width;
+       r->mmHeight     = out.mm_height;
+       r->subpixel     = out.subpixel;
+       r->count_crtcs  = out.count_crtcs;
+       r->count_clones = out.count_clones;
+       r->count_modes  = out.count_modes;
+       /* TODO we should test if these alloc & cpy fails. */
+       r->crtcs        = out.crtcs;
+       r->clones       = out.clones;
+       r->count_props  = out.count_props;
+       r->props        = drmAllocCpy(U642VOID(out.props_ptr), out.count_props, sizeof(uint32_t));
+       r->prop_values  = drmAllocCpy(U642VOID(out.prop_values_ptr), out.count_props, sizeof(uint64_t));
+       r->modes        = drmAllocCpy(U642VOID(out.modes_ptr), out.count_modes, sizeof(struct drm_mode_modeinfo));
+       r->output_type  = out.output_type;
+       r->output_type_id = out.output_type_id;
+
+err_allocs:
+       drmFree(U642VOID(out.prop_values_ptr));
+       drmFree(U642VOID(out.props_ptr));
+       drmFree(U642VOID(out.modes_ptr));
+
+       return r;
+}
+
+int drmModeAttachMode(int fd, uint32_t output_id, struct drm_mode_modeinfo *mode_info)
+{
+       struct drm_mode_mode_cmd res;
+
+       memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo));
+       res.output_id = output_id;
+
+       return ioctl(fd, DRM_IOCTL_MODE_ATTACHMODE, &res);
+}
+
+int drmModeDetachMode(int fd, uint32_t output_id, struct drm_mode_modeinfo *mode_info)
+{
+       struct drm_mode_mode_cmd res;
+
+       memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo));
+       res.output_id = output_id;
+
+       return ioctl(fd, DRM_IOCTL_MODE_DETACHMODE, &res);
+}
+
+
+drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id)
+{
+       struct drm_mode_get_property prop;
+       drmModePropertyPtr r;
+
+       prop.prop_id = property_id;
+       prop.count_enum_blobs = 0;
+       prop.count_values = 0;
+       prop.flags = 0;
+       prop.enum_blob_ptr = 0;
+       prop.values_ptr = 0;
+
+       if (ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop))
+               return 0;
+
+       if (prop.count_values)
+               prop.values_ptr = VOID2U64(drmMalloc(prop.count_values * sizeof(uint64_t)));
+
+       if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_ENUM))
+               prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum)));
+
+       if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_BLOB)) {
+               prop.values_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t)));
+               prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t)));
+       }
+
+       if (ioctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) {
+               r = NULL;
+               goto err_allocs;
+       }
+
+       if (!(r = drmMalloc(sizeof(*r))))
+               return NULL;
+       
+       r->prop_id = prop.prop_id;
+       r->count_values = prop.count_values;
+       
+       r->flags = prop.flags;
+       if (prop.count_values)
+               r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_values, sizeof(uint64_t));
+       if (prop.flags & DRM_MODE_PROP_ENUM) {
+               r->count_enums = prop.count_enum_blobs;
+               r->enums = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum));
+       } else  if (prop.flags & DRM_MODE_PROP_ENUM) {
+               r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_enum_blobs, sizeof(uint32_t));
+               r->blob_ids = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(uint32_t));
+               r->count_blobs = prop.count_enum_blobs;
+       }
+       strncpy(r->name, prop.name, DRM_PROP_NAME_LEN);
+       r->name[DRM_PROP_NAME_LEN-1] = 0;
+
+err_allocs:
+       drmFree(U642VOID(prop.values_ptr));
+       drmFree(U642VOID(prop.enum_blob_ptr));
+
+       return r;
+}
+
+void drmModeFreeProperty(drmModePropertyPtr ptr)
+{
+       if (!ptr)
+               return;
+
+       drmFree(ptr->values);
+       drmFree(ptr->enums);
+       drmFree(ptr);
+}
+
+drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id)
+{
+       struct drm_mode_get_blob blob;
+       drmModePropertyBlobPtr r;
+
+       blob.length = 0;
+       blob.data = 0;
+       blob.blob_id = blob_id;
+
+       if (ioctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
+               return NULL;
+
+       if (blob.length)
+               blob.data = VOID2U64(drmMalloc(blob.length));
+
+       if (ioctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) {
+               r = NULL;
+               goto err_allocs;
+       }
+
+       if (!(r = drmMalloc(sizeof(*r))))
+               return NULL;
+
+       r->id = blob.blob_id;
+       r->length = blob.length;
+       r->data = drmAllocCpy(U642VOID(blob.data), 1, blob.length);
+
+err_allocs:
+       drmFree(U642VOID(blob.data));
+       return r;
+}
+
+void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr)
+{
+       if (!ptr)
+               return;
+
+       drmFree(ptr->data);
+       drmFree(ptr);
+}
+
+int drmModeOutputSetProperty(int fd, uint32_t output_id, uint32_t property_id,
+                            uint64_t value)
+{
+       struct drm_mode_output_set_property osp;
+       int ret;
+
+       osp.output_id = output_id;
+       osp.prop_id = property_id;
+       osp.value = value;
+
+       if ((ret = ioctl(fd, DRM_IOCTL_MODE_SETPROPERTY, &osp)))
+               return ret;
+
+       return 0;
+}
+
+/*
+ * checks if a modesetting capable driver has attached to the pci id
+ * returns 0 if modesetting supported.
+ *  -EINVAL or invalid bus id
+ *  -ENOSYS if no modesetting support
+*/
+int drmCheckModesettingSupported(const char *busid)
+{
+#ifdef __linux__
+       char pci_dev_dir[1024];
+       int domain, bus, dev, func;
+       DIR *sysdir;
+       struct dirent *dent;
+       int found = 0, ret;
+
+       ret = sscanf(busid, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func);
+       if (ret != 4)
+               return -EINVAL;
+
+       sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/drm",
+               domain, bus, dev, func);
+
+       sysdir = opendir(pci_dev_dir);
+       if (sysdir) {
+               dent = readdir(sysdir);
+               while (dent) {
+                       if (!strncmp(dent->d_name, "controlD", 8)) {
+                               found = 1;
+                               break;
+                       }
+               
+                       dent = readdir(sysdir);
+               }
+               closedir(sysdir);
+               if (found)
+                       return 0;
+       }
+
+       sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/",
+               domain, bus, dev, func);
+
+       sysdir = opendir(pci_dev_dir);
+       if (!sysdir)
+               return -EINVAL;
+
+       dent = readdir(sysdir);
+       while (dent) {
+               if (!strncmp(dent->d_name, "drm:controlD", 12)) {
+                       found = 1;
+                       break;
+               }
+               
+               dent = readdir(sysdir);
+       }
+                       
+       closedir(sysdir);
+       if (found)
+               return 0;
+#endif
+       return -ENOSYS;
+
+}
diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h
new file mode 100644 (file)
index 0000000..edf9efe
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * \file xf86drmMode.h
+ * Header for DRM modesetting interface.
+ *
+ * \author Jakob Bornecrantz <wallbraker@gmail.com>
+ *
+ * \par Acknowledgements:
+ * Feb 2007, Dave Airlie <airlied@linux.ie>
+ */
+
+/*
+ * Copyright (c) <year> <copyright holders>
+ *
+ * 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
+ * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ */
+
+#include <drm.h>
+#include "xf86mm.h"
+
+/*
+ * This is the interface for modesetting for drm.
+ *
+ * In order to use this interface you must include either <stdint.h> or another
+ * header defining uint32_t, int32_t and uint16_t.
+ *
+ * It aims to provide a randr1.2 compatible interface for modesettings in the
+ * kernel, the interface is also ment to be used by libraries like EGL.
+ *
+ * More information can be found in randrproto.txt which can be found here:
+ * http://gitweb.freedesktop.org/?p=xorg/proto/randrproto.git
+ *
+ * There are some major diffrences to be noted. Unlike the randr1.2 proto you
+ * need to create the memory object of the framebuffer yourself with the ttm
+ * buffer object interface. This object needs to be pinned.
+ */
+
+
+typedef struct _drmModeRes {
+
+       int count_fbs;
+       uint32_t *fbs;
+
+       int count_crtcs;
+       uint32_t *crtcs;
+
+       int count_outputs;
+       uint32_t *outputs;
+
+       uint32_t min_width, max_width;
+       uint32_t min_height, max_height;
+} drmModeRes, *drmModeResPtr;
+
+typedef struct drm_mode_fb_cmd drmModeFB, *drmModeFBPtr;
+
+typedef struct _drmModePropertyBlob {
+       uint32_t id;
+       uint32_t length;
+       void *data;
+} drmModePropertyBlobRes, *drmModePropertyBlobPtr;
+
+typedef struct _drmModeProperty {
+       unsigned int prop_id;
+       unsigned int flags;
+       char name[DRM_PROP_NAME_LEN];
+       int count_values;
+       uint64_t *values; // store the blob lengths
+       int count_enums;
+       struct drm_mode_property_enum *enums;
+       int count_blobs;
+       uint32_t *blob_ids; // store the blob IDs
+} drmModePropertyRes, *drmModePropertyPtr;
+
+typedef struct _drmModeCrtc {
+       unsigned int crtc_id;
+       unsigned int buffer_id; /**< FB id to connect to 0 = disconnect*/
+
+       uint32_t x, y; /**< Position on the frameuffer */
+       uint32_t width, height;
+       int mode_valid;
+       struct drm_mode_modeinfo mode;
+
+       int count_outputs;
+       uint32_t outputs; /**< Outputs that are connected */
+
+       int count_possibles;
+       uint32_t possibles; /**< Outputs that can be connected */
+
+       int gamma_size; /**< Number of gamma stops */
+
+} drmModeCrtc, *drmModeCrtcPtr;
+
+typedef enum {
+       DRM_MODE_CONNECTED         = 1,
+       DRM_MODE_DISCONNECTED      = 2,
+       DRM_MODE_UNKNOWNCONNECTION = 3
+} drmModeConnection;
+
+typedef enum {
+       DRM_MODE_SUBPIXEL_UNKNOWN        = 1,
+       DRM_MODE_SUBPIXEL_HORIZONTAL_RGB = 2,
+       DRM_MODE_SUBPIXEL_HORIZONTAL_BGR = 3,
+       DRM_MODE_SUBPIXEL_VERTICAL_RGB   = 4,
+       DRM_MODE_SUBPIXEL_VERTICAL_BGR   = 5,
+       DRM_MODE_SUBPIXEL_NONE           = 6
+} drmModeSubPixel;
+
+typedef struct _drmModeOutput {
+       unsigned int output_id;
+
+       unsigned int crtc; /**< Crtc currently connected to */
+       unsigned int output_type;
+       unsigned int output_type_id;
+       drmModeConnection connection;
+       uint32_t mmWidth, mmHeight; /**< HxW in millimeters */
+       drmModeSubPixel subpixel;
+
+       int count_crtcs;
+       uint32_t crtcs; /**< Possible crtc to connect to */
+
+       int count_clones;
+       uint32_t clones; /**< Mask of clones */
+
+       int count_modes;
+       struct drm_mode_modeinfo *modes;
+
+       int count_props;
+       uint32_t *props; /**< List of property ids */
+       uint64_t *prop_values; /**< List of property values */
+
+} drmModeOutput, *drmModeOutputPtr;
+
+
+
+extern void drmModeFreeModeInfo( struct drm_mode_modeinfo *ptr );
+extern void drmModeFreeResources( drmModeResPtr ptr );
+extern void drmModeFreeFB( drmModeFBPtr ptr );
+extern void drmModeFreeCrtc( drmModeCrtcPtr ptr );
+extern void drmModeFreeOutput( drmModeOutputPtr ptr );
+
+/**
+ * Retrives all of the resources associated with a card.
+ */
+extern drmModeResPtr drmModeGetResources(int fd);
+
+/**
+ * Retrives the hotplug counter
+ */
+extern uint32_t drmModeGetHotplug(int fd);
+
+/*
+ * FrameBuffer manipulation.
+ */
+
+/**
+ * Retrive information about framebuffer bufferId
+ */
+extern drmModeFBPtr drmModeGetFB(int fd, uint32_t bufferId);
+
+/**
+ * Creates a new framebuffer with an buffer object as its scanout buffer.
+ */
+extern int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth,
+                       uint8_t bpp, uint32_t pitch, uint32_t bo_handle,
+                       uint32_t *buf_id);
+/**
+ * Destroies the given framebuffer.
+ */
+extern int drmModeRmFB(int fd, uint32_t bufferId);
+
+
+/*
+ * Crtc functions
+ */
+
+/**
+ * Retrive information about the ctrt crtcId
+ */
+extern drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId);
+
+/**
+ * Set the mode on a crtc crtcId with the given mode modeId.
+ */
+int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
+                   uint32_t x, uint32_t y, uint32_t *outputs, int count,
+                  struct drm_mode_modeinfo *mode);
+
+/*
+ * Cursor functions
+ */
+
+/**
+ * Set the cursor on crtc
+ */
+int drmModeSetCursor(int fd, uint32_t crtcId, drmBO *bo, uint32_t width, uint32_t height);
+
+/**
+ * Move the cursor on crtc
+ */
+int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y);
+
+/*
+ * Output manipulation
+ */
+
+/**
+ * Retrive information about the output outputId.
+ */
+extern drmModeOutputPtr drmModeGetOutput(int fd,
+               uint32_t outputId);
+
+/**
+ * Attaches the given mode to an output.
+ */
+extern int drmModeAttachMode(int fd, uint32_t outputId, struct drm_mode_modeinfo *mode_info);
+
+/**
+ * Detaches a mode from the output
+ * must be unused, by the given mode.
+ */
+extern int drmModeDetachMode(int fd, uint32_t outputId, struct drm_mode_modeinfo *mode_info);
+
+extern drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId);
+extern void drmModeFreeProperty(drmModePropertyPtr ptr);
+
+extern drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id);
+extern void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr);
+extern int drmModeOutputSetProperty(int fd, uint32_t output_id, uint32_t property_id,
+                                   uint64_t value);
+extern int drmCheckModesettingSupported(const char *busid);
index 7f6b123..2f33e5d 100644 (file)
@@ -58,7 +58,7 @@ endif
 
 # Modules for all architectures
 MODULE_LIST := drm.o tdfx.o r128.o radeon.o mga.o sis.o savage.o via.o \
-               mach64.o nv.o nouveau.o xgi.o
+               mach64.o nv.o nouveau.o xgi.o radeon_ms.o
 
 # Modules only for ix86 architectures
 ifneq (,$(findstring 86,$(MACHINE)))
@@ -92,6 +92,7 @@ NVHEADERS =     nv_drv.h $(DRMHEADERS)
 FFBHEADERS =   ffb_drv.h $(DRMHEADERS)
 NOUVEAUHEADERS = nouveau_drv.h nouveau_drm.h nouveau_reg.h $(DRMHEADERS)
 XGIHEADERS = xgi_cmdlist.h xgi_drv.h xgi_misc.h xgi_regs.h $(DRMHEADERS)
+RADEONMSHEADERS = radeon_ms_driver.h $(DRMHEADERS) 
 
 PROGS = dristat drmstat
 
@@ -286,6 +287,7 @@ CONFIG_DRM_MACH64 := n
 CONFIG_DRM_NV := n
 CONFIG_DRM_NOUVEAU := n
 CONFIG_DRM_XGI := n
+CONFIG_DRM_RADEON_MS := n
 
 # Enable module builds for the modules requested/supported.
 
@@ -325,6 +327,9 @@ endif
 ifneq (,$(findstring xgi,$(DRM_MODULES)))
 CONFIG_DRM_XGI := m
 endif
+ifneq (,$(findstring radeon_ms,$(DRM_MODULES)))
+CONFIG_DRM_RADEON_MS := m
+endif
 
 # These require AGP support
 
index e7c280d..ad62eff 100644 (file)
@@ -13,14 +13,16 @@ drm-objs    := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
                drm_sysfs.o drm_pci.o drm_agpsupport.o drm_scatter.o \
                drm_memory_debug.o ati_pcigart.o drm_sman.o \
                drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \
-               drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_bo_lock.o \
-               drm_regman.o
+               drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_crtc.o \
+               drm_edid.o drm_modes.o drm_bo_lock.o drm_regman.o
 tdfx-objs   := tdfx_drv.o
 r128-objs   := r128_drv.o r128_cce.o r128_state.o r128_irq.o
 mga-objs    := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o
 i810-objs   := i810_drv.o i810_dma.o
 i915-objs   := i915_drv.o i915_dma.o i915_irq.o i915_mem.o i915_fence.o \
-               i915_buffer.o i915_compat.o
+               i915_buffer.o intel_display.o intel_crt.o intel_lvds.o \
+               intel_sdvo.o intel_modes.o intel_i2c.o i915_init.o intel_fb.o \
+               intel_tv.o i915_compat.o
 nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \
                nouveau_object.o nouveau_irq.o nouveau_notifier.o nouveau_swmthd.o \
                nouveau_sgdma.o nouveau_dma.o nouveau_buffer.o nouveau_fence.o \
@@ -32,6 +34,13 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \
                nv40_graph.o nv50_graph.o \
                nv04_instmem.o nv50_instmem.o
 radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o
+radeon_ms-objs := radeon_ms_drv.o radeon_ms_drm.o radeon_ms_family.o \
+               radeon_ms_state.o radeon_ms_bo.o radeon_ms_irq.o \
+               radeon_ms_bus.o radeon_ms_fence.o \
+               radeon_ms_cp.o radeon_ms_cp_mc.o radeon_ms_i2c.o \
+               radeon_ms_output.o radeon_ms_crtc.o radeon_ms_fb.o \
+               radeon_ms_exec.o radeon_ms_gpu.o radeon_ms_dac.o \
+               radeon_ms_properties.o radeon_ms_rom.o radeon_ms_combios.o
 sis-objs    := sis_drv.o sis_mm.o
 ffb-objs    := ffb_drv.o ffb_context.o
 savage-objs := savage_drv.o savage_bci.o savage_state.o
@@ -45,6 +54,7 @@ xgi-objs    := xgi_cmdlist.o xgi_drv.o xgi_fb.o xgi_misc.o xgi_pcie.o \
 ifeq ($(CONFIG_COMPAT),y)
 drm-objs    += drm_ioc32.o
 radeon-objs += radeon_ioc32.o
+radeon_ms-objs += radeon_ms_compat.o
 mga-objs    += mga_ioc32.o
 r128-objs   += r128_ioc32.o
 i915-objs   += i915_ioc32.o
@@ -67,3 +77,4 @@ obj-$(CONFIG_DRM_MACH64)+= mach64.o
 obj-$(CONFIG_DRM_NV)    += nv.o
 obj-$(CONFIG_DRM_NOUVEAU) += nouveau.o
 obj-$(CONFIG_DRM_XGI)   += xgi.o
+obj-$(CONFIG_DRM_RADEON_MS) += radeon_ms.o
index 1fea807..4797485 100644 (file)
@@ -106,6 +106,7 @@ struct drm_file;
 #define DRIVER_IRQ_SHARED  0x80
 #define DRIVER_DMA_QUEUE   0x100
 #define DRIVER_FB_DMA      0x200
+#define DRIVER_MODESET     0x400
 
 
 /*@}*/
@@ -260,11 +261,11 @@ struct drm_file;
  */
 #define LOCK_TEST_WITH_RETURN( dev, file_priv )                                \
 do {                                                                   \
-       if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) ||           \
-            dev->lock.file_priv != file_priv ) {                       \
+       if ( !_DRM_LOCK_IS_HELD( file_priv->master->lock.hw_lock->lock ) ||             \
+            file_priv->master->lock.file_priv != file_priv )   {                       \
                DRM_ERROR( "%s called without lock held, held  %d owner %p %p\n",\
-                          __FUNCTION__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\
-                          dev->lock.file_priv, file_priv );            \
+                          __FUNCTION__, _DRM_LOCK_IS_HELD( file_priv->master->lock.hw_lock->lock ),\
+                          file_priv->master->lock.file_priv, file_priv );              \
                return -EINVAL;                                         \
        }                                                               \
 } while (0)
@@ -298,6 +299,7 @@ typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd,
 #define DRM_AUTH        0x1
 #define DRM_MASTER      0x2
 #define DRM_ROOT_ONLY   0x4
+#define DRM_CONTROL_ALLOW 0x8 // allow ioctl to operate on control node 
 
 struct drm_ioctl_desc {
        unsigned int cmd;
@@ -407,7 +409,6 @@ enum drm_ref_type {
 /** File private data */
 struct drm_file {
        int authenticated;
-       int master;
        pid_t pid;
        uid_t uid;
        drm_magic_t magic;
@@ -429,6 +430,11 @@ struct drm_file {
        struct drm_open_hash refd_object_hash[_DRM_NO_REF_TYPES];
        struct file *filp;
        void *driver_priv;
+
+       int is_master; /* this file private is a master for a minor */
+       struct drm_master *master; /* master this node is currently associated with
+                                     N.B. not always minor->master */
+       struct list_head fbs;
 };
 
 /** Wait queue */
@@ -563,6 +569,8 @@ struct drm_map_list {
        struct drm_map *map;                    /**< mapping */
        uint64_t user_token;
        struct drm_mm_node *file_offset_node;
+       struct drm_master *master; /** if this map is associated with a specific
+                                      master */
 };
 
 typedef struct drm_map drm_local_map_t;
@@ -601,6 +609,29 @@ struct drm_ati_pcigart_info {
 };
 
 #include "drm_objects.h"
+#include "drm_crtc.h"
+
+/* per-master structure */
+struct drm_master {
+       
+       struct list_head head; /**< each minor contains a list of masters */
+       struct drm_minor *minor; /**< link back to minor we are a master for */
+
+       char *unique;                   /**< Unique identifier: e.g., busid */
+       int unique_len;                 /**< Length of unique field */
+
+       int blocked;                    /**< Blocked due to VC switch? */
+
+       /** \name Authentication */
+       /*@{ */
+       struct drm_open_hash magiclist;
+       struct list_head magicfree;
+       /*@} */
+
+       struct drm_lock_data lock;              /**< Information on hardware lock */
+
+       void *driver_priv; /**< Private structure for driver to use */
+};
 
 /**
  * DRM driver structure. This structure represent the common code for
@@ -701,6 +732,15 @@ struct drm_driver {
        void (*set_version) (struct drm_device *dev,
                             struct drm_set_version *sv);
 
+       /* FB routines, if present */
+       int (*fb_probe)(struct drm_device *dev, struct drm_crtc *crtc);
+       int (*fb_remove)(struct drm_device *dev, struct drm_crtc *crtc);
+       int (*fb_resize)(struct drm_device *dev, struct drm_crtc *crtc);
+
+       /* Master routines */
+       int (*master_create)(struct drm_device *dev, struct drm_master *master);
+       void (*master_destroy)(struct drm_device *dev, struct drm_master *master);
+
        struct drm_fence_driver *fence_driver;
        struct drm_bo_driver *bo_driver;
 
@@ -722,6 +762,8 @@ struct drm_driver {
 
 #define DRM_MINOR_UNASSIGNED 0
 #define DRM_MINOR_LEGACY 1
+#define DRM_MINOR_CONTROL 2
+#define DRM_MINOR_RENDER 3
 
 /**
  * DRM minor structure. This structure represents a drm minor number.
@@ -732,8 +774,15 @@ struct drm_minor {
        dev_t device;                   /**< Device number for mknod */
        struct device kdev;             /**< Linux device */
        struct drm_device *dev;
+       /* for render nodes */
        struct proc_dir_entry *dev_root;  /**< proc directory entry */
        struct class_device *dev_class;
+
+       /* for control nodes - a pointer to the current master for this control node */
+       struct drm_master *master; /* currently active master for this node */
+       struct list_head master_list;
+
+       /* possibly needs a list of configured modesetting pieces */
 };
 
 
@@ -742,13 +791,9 @@ struct drm_minor {
  * may contain multiple heads.
  */
 struct drm_device {
-       char *unique;                   /**< Unique identifier: e.g., busid */
-       int unique_len;                 /**< Length of unique field */
        char *devname;                  /**< For /proc/interrupts */
        int if_version;                 /**< Highest interface version set */
 
-       int blocked;                    /**< Blocked due to VC switch? */
-
        /** \name Locks */
        /*@{ */
        spinlock_t count_lock;          /**< For inuse, drm_device::open_count, drm_device::buf_use */
@@ -771,12 +816,6 @@ struct drm_device {
        atomic_t counts[15];
        /*@} */
 
-       /** \name Authentication */
-       /*@{ */
-       struct list_head filelist;
-       struct drm_open_hash magiclist;
-       struct list_head magicfree;
-       /*@} */
 
        /** \name Memory management */
        /*@{ */
@@ -797,7 +836,9 @@ struct drm_device {
        struct idr ctx_idr;
 
        struct list_head vmalist;       /**< List of vmas (for debugging) */
-       struct drm_lock_data lock;              /**< Information on hardware lock */
+
+       struct list_head filelist;
+
        /*@} */
 
        /** \name DMA queues (contexts) */
@@ -809,6 +850,7 @@ struct drm_device {
        struct drm_device_dma *dma;             /**< Optional pointer for DMA support */
        /*@} */
 
+
        /** \name Context support */
        /*@{ */
        int irq;                        /**< Interrupt used by board */
@@ -871,6 +913,9 @@ struct drm_device {
        struct drm_driver *driver;
        drm_local_map_t *agp_buffer_map;
        unsigned int agp_buffer_token;
+
+       /* minor number for control node */
+       struct drm_minor *control;
        struct drm_minor *primary;              /**< render type primary screen head */
 
        struct drm_fence_manager fm;
@@ -881,6 +926,9 @@ struct drm_device {
        spinlock_t drw_lock;
        struct idr drw_idr;
        /*@} */
+
+       /* DRM mode setting */
+       struct drm_mode_config mode_config;
 };
 
 #if __OS_HAS_AGP
@@ -892,6 +940,17 @@ struct drm_agp_ttm_backend {
 };
 #endif
 
+typedef struct ati_pcigart_ttm_backend {
+       struct drm_ttm_backend backend;
+       int populated;
+       void (*gart_flush_fn)(struct drm_device *dev);
+       struct drm_ati_pcigart_info *gart_info;
+       unsigned long offset;
+       struct page **pages;
+       int num_pages;
+       int bound;
+       struct drm_device *dev;
+} ati_pcigart_ttm_backend_t;
 
 static __inline__ int drm_core_check_feature(struct drm_device *dev,
                                             int feature)
@@ -1185,6 +1244,8 @@ extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle);
 extern struct drm_ttm_backend *drm_agp_init_ttm(struct drm_device *dev);
 extern void drm_agp_chipset_flush(struct drm_device *dev);
                                /* Stub support (drm_stub.h) */
+extern struct drm_master *drm_get_master(struct drm_minor *minor);
+extern void drm_put_master(struct drm_master *master);
 extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
                     struct drm_driver *driver);
 extern int drm_put_dev(struct drm_device *dev);
@@ -1242,6 +1303,7 @@ extern int drm_mm_clean(struct drm_mm *mm);
 extern unsigned long drm_mm_tail_space(struct drm_mm *mm);
 extern int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size);
 extern int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size);
+extern void drm_mm_print(struct drm_mm *mm, const char *name);
 
 static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block)
 {
index c904a91..20c8a63 100644 (file)
  * the one with matching magic number, while holding the drm_device::struct_mutex
  * lock.
  */
-static struct drm_file *drm_find_file(struct drm_device * dev, drm_magic_t magic)
+static struct drm_file *drm_find_file(struct drm_master *master , drm_magic_t magic)
 {
        struct drm_file *retval = NULL;
        struct drm_magic_entry *pt;
        struct drm_hash_item *hash;
+       struct drm_device *dev = master->minor->dev;
 
        mutex_lock(&dev->struct_mutex);
-       if (!drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
+       if (!drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) {
                pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item);
                retval = pt->priv;
        }
@@ -71,11 +72,11 @@ static struct drm_file *drm_find_file(struct drm_device * dev, drm_magic_t magic
  * associated the magic number hash key in drm_device::magiclist, while holding
  * the drm_device::struct_mutex lock.
  */
-static int drm_add_magic(struct drm_device * dev, struct drm_file * priv,
+static int drm_add_magic(struct drm_master *master, struct drm_file * priv,
                         drm_magic_t magic)
 {
        struct drm_magic_entry *entry;
-
+       struct drm_device *dev = master->minor->dev;
        DRM_DEBUG("%d\n", magic);
 
        entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC);
@@ -85,8 +86,8 @@ static int drm_add_magic(struct drm_device * dev, struct drm_file * priv,
        entry->priv = priv;
        entry->hash_item.key = (unsigned long)magic;
        mutex_lock(&dev->struct_mutex);
-       drm_ht_insert_item(&dev->magiclist, &entry->hash_item);
-       list_add_tail(&entry->head, &dev->magicfree);
+       drm_ht_insert_item(&master->magiclist, &entry->hash_item);
+       list_add_tail(&entry->head, &master->magicfree);
        mutex_unlock(&dev->struct_mutex);
 
        return 0;
@@ -101,20 +102,21 @@ static int drm_add_magic(struct drm_device * dev, struct drm_file * priv,
  * Searches and unlinks the entry in drm_device::magiclist with the magic
  * number hash key, while holding the drm_device::struct_mutex lock.
  */
-static int drm_remove_magic(struct drm_device * dev, drm_magic_t magic)
+static int drm_remove_magic(struct drm_master *master, drm_magic_t magic)
 {
        struct drm_magic_entry *pt;
        struct drm_hash_item *hash;
+       struct drm_device *dev = master->minor->dev;
 
        DRM_DEBUG("%d\n", magic);
 
        mutex_lock(&dev->struct_mutex);
-       if (drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
+       if (drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) {
                mutex_unlock(&dev->struct_mutex);
                return -EINVAL;
        }
        pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item);
-       drm_ht_remove_item(&dev->magiclist, hash);
+       drm_ht_remove_item(&master->magiclist, hash);
        list_del(&pt->head);
        mutex_unlock(&dev->struct_mutex);
 
@@ -152,9 +154,9 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
                                ++sequence;     /* reserve 0 */
                        auth->magic = sequence++;
                        spin_unlock(&lock);
-               } while (drm_find_file(dev, auth->magic));
+               } while (drm_find_file(file_priv->master, auth->magic));
                file_priv->magic = auth->magic;
-               drm_add_magic(dev, file_priv, auth->magic);
+               drm_add_magic(file_priv->master, file_priv, auth->magic);
        }
 
        DRM_DEBUG("%u\n", auth->magic);
@@ -180,9 +182,9 @@ int drm_authmagic(struct drm_device *dev, void *data,
        struct drm_file *file;
 
        DRM_DEBUG("%u\n", auth->magic);
-       if ((file = drm_find_file(dev, auth->magic))) {
+       if ((file = drm_find_file(file_priv->master, auth->magic))) {
                file->authenticated = 1;
-               drm_remove_magic(dev, auth->magic);
+               drm_remove_magic(file_priv->master, auth->magic);
                return 0;
        }
        return -EINVAL;
index fd3cf9d..1d3f87e 100644 (file)
@@ -574,7 +574,6 @@ void drm_putback_buffer_objects(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_putback_buffer_objects);
 
-
 /*
  * Note. The caller has to register (if applicable)
  * and deregister fence object usage.
@@ -1758,7 +1757,7 @@ int drm_buffer_object_create(struct drm_device *dev,
        size += buffer_start & ~PAGE_MASK;
        num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
        if (num_pages == 0) {
-               DRM_ERROR("Illegal buffer object size.\n");
+               DRM_ERROR("Illegal buffer object size %ld.\n", size);
                return -EINVAL;
        }
 
@@ -2360,6 +2359,7 @@ out:
        mutex_unlock(&dev->struct_mutex);
        return ret;
 }
+EXPORT_SYMBOL(drm_bo_driver_finish);
 
 /*
  * This function is intended to be called on drm driver load.
index 30e0f43..536ff5d 100644 (file)
@@ -147,6 +147,7 @@ void drm_mem_reg_iounmap(struct drm_device *dev, struct drm_bo_mem_reg *mem,
        if (virtual && (man->flags & _DRM_FLAG_NEEDS_IOREMAP))
                iounmap(virtual);
 }
+EXPORT_SYMBOL(drm_mem_reg_iounmap);
 
 static int drm_copy_io_page(void *dst, void *src, unsigned long page)
 {
index 75c75c2..031f8ba 100644 (file)
@@ -52,9 +52,9 @@ struct drm_map_list *drm_find_matching_map(struct drm_device *dev, drm_local_map
 {
        struct drm_map_list *entry;
        list_for_each_entry(entry, &dev->maplist, head) {
-               if (entry->map && map->type == entry->map->type &&
-                   ((entry->map->offset == map->offset) ||
-                    (map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) {
+               if (entry->map && (entry->master == dev->primary->master) && (map->type == entry->map->type) &&
+                   ((entry->map->offset == map->offset) || 
+                    ((map->type == _DRM_SHM) && (map->flags&_DRM_CONTAINS_LOCK)))) {
                        return entry;
                }
        }
@@ -209,12 +209,12 @@ static int drm_addmap_core(struct drm_device *dev, unsigned int offset,
                map->offset = (unsigned long)map->handle;
                if (map->flags & _DRM_CONTAINS_LOCK) {
                        /* Prevent a 2nd X Server from creating a 2nd lock */
-                       if (dev->lock.hw_lock != NULL) {
+                       if (dev->primary->master->lock.hw_lock != NULL) {
                                vfree(map->handle);
                                drm_free(map, sizeof(*map), DRM_MEM_MAPS);
                                return -EBUSY;
                        }
-                       dev->sigdata.lock = dev->lock.hw_lock = map->handle;    /* Pointer to lock */
+                       dev->sigdata.lock = dev->primary->master->lock.hw_lock = map->handle;   /* Pointer to lock */
                }
                break;
        case _DRM_AGP: {
@@ -318,6 +318,7 @@ static int drm_addmap_core(struct drm_device *dev, unsigned int offset,
        list->user_token = list->hash.key << PAGE_SHIFT;
        mutex_unlock(&dev->struct_mutex);
 
+       list->master = dev->primary->master;
        *maplist = list;
        return 0;
 }
@@ -412,6 +413,9 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)
                break;
        case _DRM_SHM:
                vfree(map->handle);
+               dev->sigdata.lock = dev->primary->master->lock.hw_lock = NULL;   /* SHM removed */
+               dev->primary->master->lock.file_priv = NULL;
+               wake_up_interruptible(&dev->primary->master->lock.lock_queue);
                break;
        case _DRM_AGP:
        case _DRM_SCATTER_GATHER:
index d4044cb..9b98266 100644 (file)
@@ -730,6 +730,56 @@ void *idr_replace(struct idr *idp, void *ptr, int id)
 EXPORT_SYMBOL(idr_replace);
 #endif
 
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+static __inline__ unsigned long __round_jiffies(unsigned long j, int cpu)
+{
+       int rem;
+       unsigned long original = j;
+
+       j += cpu * 3;
+
+       rem = j % HZ;
+
+       if (rem < HZ/4) /* round down */
+               j = j - rem;
+       else /* round up */
+               j = j - rem + HZ;
+
+       /* now that we have rounded, subtract the extra skew again */
+       j -= cpu * 3;
+
+       if (j <= jiffies) /* rounding ate our timeout entirely; */
+               return original;
+       return j;
+}
+
+static __inline__ unsigned long __round_jiffies_relative(unsigned long j, int cpu)
+{
+       return  __round_jiffies(j + jiffies, cpu) - jiffies;
+}
+
+unsigned long round_jiffies_relative(unsigned long j)
+{
+       return __round_jiffies_relative(j, raw_smp_processor_id());
+}
+EXPORT_SYMBOL(round_jiffies_relative);
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn)
+{
+    struct pci_dev *dev = NULL;
+
+    while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+        if (pci_domain_nr(dev->bus) == 0 &&
+           (dev->bus->number == bus && dev->devfn == devfn))
+            return dev;
+   }
+   return NULL;
+}
+EXPORT_SYMBOL(pci_get_bus_and_slot);
+#endif
+
 #if defined(DRM_KMAP_ATOMIC_PROT_PFN) && defined(CONFIG_HIMEM)
 #define drm_kmap_get_fixmap_pte(vaddr)                                 \
        pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), vaddr), (vaddr)), (vaddr))
@@ -756,7 +806,5 @@ void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type,
 }
 
 EXPORT_SYMBOL(kmap_atomic_prot_pfn);
-
 #endif
 
-
index 8f2d9a9..03838a1 100644 (file)
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
 #undef DRM_IRQ_ARGS
 #define DRM_IRQ_ARGS           int irq, void *arg, struct pt_regs *regs
+
+typedef _Bool bool;
+enum {
+        false   = 0,
+        true    = 1
+};
+
 #endif
 
 #ifndef list_for_each_safe
@@ -152,7 +159,7 @@ static __inline__ void *kcalloc(size_t nmemb, size_t size, int flags)
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
 #define vmalloc_user(_size) ({void * tmp = vmalloc(_size);   \
-      if (tmp) memset(tmp, 0, size);                        \
+      if (tmp) memset(tmp, 0, _size);                       \
       (tmp);})
 #endif
 
@@ -325,7 +332,15 @@ void *idr_replace(struct idr *idp, void *ptr, int id);
 #endif
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
-typedef _Bool                   bool;
+extern unsigned long round_jiffies_relative(unsigned long j);
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
+extern struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn);
+#endif
+
+#ifndef PM_EVENT_PRETHAW 
+#define PM_EVENT_PRETHAW 3
 #endif
 
 #if (defined(CONFIG_X86) && defined(CONFIG_X86_32) && defined(CONFIG_HIMEM))
index 83ad291..febee9f 100644 (file)
@@ -257,12 +257,13 @@ static int drm_context_switch(struct drm_device *dev, int old, int new)
  * hardware lock is held, clears the drm_device::context_flag and wakes up
  * drm_device::context_wait.
  */
-static int drm_context_switch_complete(struct drm_device *dev, int new)
+static int drm_context_switch_complete(struct drm_device *dev, 
+                                      struct drm_file *file_priv, int new)
 {
        dev->last_context = new;        /* PRE/POST: This is the _only_ writer. */
        dev->last_switch = jiffies;
 
-       if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
+       if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock)) {
                DRM_ERROR("Lock isn't held after context switch\n");
        }
 
@@ -421,7 +422,7 @@ int drm_newctx(struct drm_device *dev, void *data,
        struct drm_ctx *ctx = data;
 
        DRM_DEBUG("%d\n", ctx->handle);
-       drm_context_switch_complete(dev, ctx->handle);
+       drm_context_switch_complete(dev, file_priv, ctx->handle);
 
        return 0;
 }
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c
new file mode 100644 (file)
index 0000000..be49190
--- /dev/null
@@ -0,0 +1,2455 @@
+/*
+ * Copyright (c) 2006-2007 Intel Corporation
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
+ *
+ * DRM core CRTC related functions
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ *
+ * Authors:
+ *      Keith Packard
+ *     Eric Anholt <eric@anholt.net>
+ *      Dave Airlie <airlied@linux.ie>
+ *      Jesse Barnes <jesse.barnes@intel.com>
+ */
+#include <linux/list.h>
+#include "drm.h"
+#include "drmP.h"
+#include "drm_crtc.h"
+
+struct drm_prop_enum_list {
+       int type;
+       char *name;
+};
+
+/*
+ * Global properties
+ */
+static struct drm_prop_enum_list drm_dpms_enum_list[] =
+{ { DPMSModeOn, "On" },
+  { DPMSModeStandby, "Standby" },
+  { DPMSModeSuspend, "Suspend" },
+  { DPMSModeOff, "Off" }
+};
+static struct drm_prop_enum_list drm_conn_enum_list[] = 
+{ { ConnectorUnknown, "Unknown" },
+  { ConnectorVGA, "VGA" },
+  { ConnectorDVII, "DVI-I" },
+  { ConnectorDVID, "DVI-D" },
+  { ConnectorDVIA, "DVI-A" },
+  { ConnectorComposite, "Composite" },
+  { ConnectorSVIDEO, "SVIDEO" },
+  { ConnectorLVDS, "LVDS" },
+  { ConnectorComponent, "Component" },
+  { Connector9PinDIN, "9-pin DIN" },
+  { ConnectorDisplayPort, "DisplayPort" },
+  { ConnectorHDMIA, "HDMI Type A" },
+  { ConnectorHDMIB, "HDMI Type B" },
+};
+static struct drm_prop_enum_list drm_output_enum_list[] =
+{ { DRM_MODE_OUTPUT_NONE, "None" },
+  { DRM_MODE_OUTPUT_DAC, "DAC" },
+  { DRM_MODE_OUTPUT_TMDS, "TMDS" },
+  { DRM_MODE_OUTPUT_LVDS, "LVDS" },
+  { DRM_MODE_OUTPUT_TVDAC, "TV" },
+};
+
+char *drm_get_output_name(struct drm_output *output)
+{
+       static char buf[32];
+
+       snprintf(buf, 32, "%s-%d", drm_output_enum_list[output->output_type].name,
+                output->output_type_id);
+       return buf;
+}
+
+/**
+ * drm_idr_get - allocate a new identifier
+ * @dev: DRM device
+ * @ptr: object pointer, used to generate unique ID
+ *
+ * LOCKING:
+ * Caller must hold DRM mode_config lock.
+ *
+ * Create a unique identifier based on @ptr in @dev's identifier space.  Used
+ * for tracking modes, CRTCs and outputs.
+ *
+ * RETURNS:
+ * New unique (relative to other objects in @dev) integer identifier for the
+ * object.
+ */
+int drm_idr_get(struct drm_device *dev, void *ptr)
+{
+       int new_id = 0;
+       int ret;
+again:
+       if (idr_pre_get(&dev->mode_config.crtc_idr, GFP_KERNEL) == 0) {
+               DRM_ERROR("Ran out memory getting a mode number\n");
+               return 0;
+       }
+
+       ret = idr_get_new_above(&dev->mode_config.crtc_idr, ptr, 1, &new_id);
+       if (ret == -EAGAIN)
+               goto again;     
+
+       return new_id;
+}
+
+/**
+ * drm_idr_put - free an identifer
+ * @dev: DRM device
+ * @id: ID to free
+ *
+ * LOCKING:
+ * Caller must hold DRM mode_config lock.
+ *
+ * Free @id from @dev's unique identifier pool.
+ */
+void drm_idr_put(struct drm_device *dev, int id)
+{
+       idr_remove(&dev->mode_config.crtc_idr, id);
+}
+
+/**
+ * drm_crtc_from_fb - find the CRTC structure associated with an fb
+ * @dev: DRM device
+ * @fb: framebuffer in question
+ *
+ * LOCKING:
+ * Caller must hold mode_config lock.
+ *
+ * Find CRTC in the mode_config structure that matches @fb.
+ *
+ * RETURNS:
+ * Pointer to the CRTC or NULL if it wasn't found.
+ */
+struct drm_crtc *drm_crtc_from_fb(struct drm_device *dev,
+                                 struct drm_framebuffer *fb)
+{
+       struct drm_crtc *crtc;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               if (crtc->fb == fb)
+                       return crtc;
+       }
+       return NULL;
+}
+
+/**
+ * drm_framebuffer_create - create a new framebuffer object
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Creates a new framebuffer objects and adds it to @dev's DRM mode_config.
+ *
+ * RETURNS:
+ * Pointer to new framebuffer or NULL on error.
+ */
+struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev)
+{
+       struct drm_framebuffer *fb;
+
+       fb = kzalloc(sizeof(struct drm_framebuffer), GFP_KERNEL);
+       if (!fb)
+               return NULL;
+       
+       fb->id = drm_idr_get(dev, fb);
+       fb->dev = dev;
+       dev->mode_config.num_fb++;
+       list_add(&fb->head, &dev->mode_config.fb_list);
+
+       return fb;
+}
+EXPORT_SYMBOL(drm_framebuffer_create);
+
+/**
+ * drm_framebuffer_destroy - remove a framebuffer object
+ * @fb: framebuffer to remove
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Scans all the CRTCs in @dev's mode_config.  If they're using @fb, removes
+ * it, setting it to NULL.
+ */
+void drm_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+       struct drm_device *dev = fb->dev;
+       struct drm_crtc *crtc;
+
+       /* remove from any CRTC */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               if (crtc->fb == fb)
+                       crtc->fb = NULL;
+       }
+
+       drm_idr_put(dev, fb->id);
+       list_del(&fb->head);
+       dev->mode_config.num_fb--;
+
+       kfree(fb);
+}
+EXPORT_SYMBOL(drm_framebuffer_destroy);
+
+/**
+ * drm_crtc_create - create a new CRTC object
+ * @dev: DRM device
+ * @funcs: callbacks for the new CRTC
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Creates a new CRTC object and adds it to @dev's mode_config structure.
+ *
+ * RETURNS:
+ * Pointer to new CRTC object or NULL on error.
+ */
+struct drm_crtc *drm_crtc_create(struct drm_device *dev,
+                                const struct drm_crtc_funcs *funcs)
+{
+       struct drm_crtc *crtc;
+
+       crtc = kzalloc(sizeof(struct drm_crtc), GFP_KERNEL);
+       if (!crtc)
+               return NULL;
+
+       crtc->dev = dev;
+       crtc->funcs = funcs;
+
+       crtc->id = drm_idr_get(dev, crtc);
+
+       list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
+       dev->mode_config.num_crtc++;
+
+       return crtc;
+}
+EXPORT_SYMBOL(drm_crtc_create);
+
+/**
+ * drm_crtc_destroy - remove a CRTC object
+ * @crtc: CRTC to remove
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Cleanup @crtc.  Calls @crtc's cleanup function, then removes @crtc from
+ * its associated DRM device's mode_config.  Frees it afterwards.
+ */
+void drm_crtc_destroy(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+
+       if (crtc->funcs->cleanup)
+               (*crtc->funcs->cleanup)(crtc);
+
+       drm_idr_put(dev, crtc->id);
+       list_del(&crtc->head);
+       dev->mode_config.num_crtc--;
+       kfree(crtc);
+}
+EXPORT_SYMBOL(drm_crtc_destroy);
+
+/**
+ * drm_crtc_in_use - check if a given CRTC is in a mode_config
+ * @crtc: CRTC to check
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Walk @crtc's DRM device's mode_config and see if it's in use.
+ *
+ * RETURNS:
+ * True if @crtc is part of the mode_config, false otherwise.
+ */
+bool drm_crtc_in_use(struct drm_crtc *crtc)
+{
+       struct drm_output *output;
+       struct drm_device *dev = crtc->dev;
+       /* FIXME: Locking around list access? */
+       list_for_each_entry(output, &dev->mode_config.output_list, head)
+               if (output->crtc == crtc)
+                       return true;
+       return false;
+}
+EXPORT_SYMBOL(drm_crtc_in_use);
+
+/*
+ * Detailed mode info for a standard 640x480@60Hz monitor
+ */
+static struct drm_display_mode std_mode[] = {
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 25200, 640, 656,
+                  752, 800, 0, 480, 490, 492, 525, 0,
+                  V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */
+};
+
+/**
+ * drm_crtc_probe_output_modes - get complete set of display modes
+ * @dev: DRM device
+ * @maxX: max width for modes
+ * @maxY: max height for modes
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Based on @dev's mode_config layout, scan all the outputs and try to detect
+ * modes on them.  Modes will first be added to the output's probed_modes
+ * list, then culled (based on validity and the @maxX, @maxY parameters) and
+ * put into the normal modes list.
+ *
+ * Intended to be used either at bootup time or when major configuration
+ * changes have occurred.
+ *
+ * FIXME: take into account monitor limits
+ */
+void drm_crtc_probe_single_output_modes(struct drm_output *output, int maxX, int maxY)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_display_mode *mode, *t;
+       int ret;
+       //if (maxX == 0 || maxY == 0) 
+       // TODO
+
+       /* set all modes to the unverified state */
+       list_for_each_entry_safe(mode, t, &output->modes, head)
+               mode->status = MODE_UNVERIFIED;
+               
+       output->status = (*output->funcs->detect)(output);
+       
+       if (output->status == output_status_disconnected) {
+               DRM_DEBUG("%s is disconnected\n", drm_get_output_name(output));
+               /* TODO set EDID to NULL */
+               return;
+       }
+       
+       ret = (*output->funcs->get_modes)(output);
+       
+       if (ret) {
+               drm_mode_output_list_update(output);
+       }
+       
+       if (maxX && maxY)
+               drm_mode_validate_size(dev, &output->modes, maxX,
+                                      maxY, 0);
+       list_for_each_entry_safe(mode, t, &output->modes, head) {
+               if (mode->status == MODE_OK)
+                       mode->status = (*output->funcs->mode_valid)(output,mode);
+       }
+       
+       
+       drm_mode_prune_invalid(dev, &output->modes, TRUE);
+       
+       if (list_empty(&output->modes)) {
+               struct drm_display_mode *stdmode;
+               
+               DRM_DEBUG("No valid modes on %s\n", drm_get_output_name(output));
+               
+               /* Should we do this here ???
+                * When no valid EDID modes are available we end up
+                * here and bailed in the past, now we add a standard
+                * 640x480@60Hz mode and carry on.
+                */
+               stdmode = drm_mode_duplicate(dev, &std_mode[0]);
+               drm_mode_probed_add(output, stdmode);
+               drm_mode_list_concat(&output->probed_modes,
+                                    &output->modes);
+               
+               DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n",
+                         drm_get_output_name(output));
+       }
+       
+       drm_mode_sort(&output->modes);
+       
+       DRM_DEBUG("Probed modes for %s\n", drm_get_output_name(output));
+       list_for_each_entry_safe(mode, t, &output->modes, head) {
+               mode->vrefresh = drm_mode_vrefresh(mode);
+               
+               drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+               drm_mode_debug_printmodeline(dev, mode);
+       }
+}
+
+void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY)
+{
+       struct drm_output *output;
+
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+               drm_crtc_probe_single_output_modes(output, maxX, maxY);
+       }
+}
+EXPORT_SYMBOL(drm_crtc_probe_output_modes);
+
+/**
+ * drm_crtc_set_mode - set a mode
+ * @crtc: CRTC to program
+ * @mode: mode to use
+ * @x: width of mode
+ * @y: height of mode
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Try to set @mode on @crtc.  Give @crtc and its associated outputs a chance
+ * to fixup or reject the mode prior to trying to set it.
+ *
+ * RETURNS:
+ * True if the mode was set successfully, or false otherwise.
+ */
+bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                      int x, int y)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_display_mode *adjusted_mode, saved_mode;
+       int saved_x, saved_y;
+       bool didLock = false;
+       struct drm_output *output;
+       bool ret = true;
+
+       adjusted_mode = drm_mode_duplicate(dev, mode);
+
+       crtc->enabled = drm_crtc_in_use(crtc);
+
+       if (!crtc->enabled)
+               return true;
+
+       didLock = crtc->funcs->lock(crtc);
+
+       saved_mode = crtc->mode;
+       saved_x = crtc->x;
+       saved_y = crtc->y;
+       
+       /* Update crtc values up front so the driver can rely on them for mode
+        * setting.
+        */
+       crtc->mode = *mode;
+       crtc->x = x;
+       crtc->y = y;
+
+       if (drm_mode_equal(&saved_mode, &crtc->mode)) {
+               if (saved_x != crtc->x || saved_y != crtc->y) {
+                       crtc->funcs->mode_set_base(crtc, crtc->x, crtc->y);
+                       goto done;
+               }
+       }
+
+       /* Pass our mode to the outputs and the CRTC to give them a chance to
+        * adjust it according to limitations or output properties, and also
+        * a chance to reject the mode entirely.
+        */
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+               
+               if (output->crtc != crtc)
+                       continue;
+               
+               if (!(ret = output->funcs->mode_fixup(output, mode, adjusted_mode))) {
+                       goto done;
+               }
+       }
+       
+       if (!(ret = crtc->funcs->mode_fixup(crtc, mode, adjusted_mode))) {
+               goto done;
+       }
+
+       /* Prepare the outputs and CRTCs before setting the mode. */
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+
+               if (output->crtc != crtc)
+                       continue;
+               
+               /* Disable the output as the first thing we do. */
+               output->funcs->prepare(output);
+       }
+       
+       crtc->funcs->prepare(crtc);
+       
+       /* Set up the DPLL and any output state that needs to adjust or depend
+        * on the DPLL.
+        */
+       crtc->funcs->mode_set(crtc, mode, adjusted_mode, x, y);
+
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+
+               if (output->crtc != crtc)
+                       continue;
+               
+               DRM_INFO("%s: set mode %s %x\n", drm_get_output_name(output), mode->name, mode->mode_id);
+
+               output->funcs->mode_set(output, mode, adjusted_mode);
+       }
+       
+       /* Now, enable the clocks, plane, pipe, and outputs that we set up. */
+       crtc->funcs->commit(crtc);
+
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+
+               if (output->crtc != crtc)
+                       continue;
+               
+               output->funcs->commit(output);
+
+#if 0 // TODO def RANDR_12_INTERFACE
+               if (output->randr_output)
+                       RRPostPendingProperties (output->randr_output);
+#endif
+       }
+       
+       /* XXX free adjustedmode */
+       drm_mode_destroy(dev, adjusted_mode);
+       /* TODO */
+//     if (scrn->pScreen)
+//             drm_crtc_set_screen_sub_pixel_order(dev);
+
+done:
+       if (!ret) { 
+               crtc->mode = saved_mode;
+               crtc->x = saved_x;
+               crtc->y = saved_y;
+       } 
+
+       if (didLock)
+               crtc->funcs->unlock (crtc);
+       
+       return ret;
+}
+EXPORT_SYMBOL(drm_crtc_set_mode);
+
+/**
+ * drm_disable_unused_functions - disable unused objects
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * If an output or CRTC isn't part of @dev's mode_config, it can be disabled
+ * by calling its dpms function, which should power it off.
+ */
+void drm_disable_unused_functions(struct drm_device *dev)
+{
+       struct drm_output *output;
+       struct drm_crtc *crtc;
+
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+               if (!output->crtc)
+                       (*output->funcs->dpms)(output, DPMSModeOff);
+       }
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               if (!crtc->enabled)
+                       crtc->funcs->dpms(crtc, DPMSModeOff);
+       }
+}
+EXPORT_SYMBOL(drm_disable_unused_functions);
+
+/**
+ * drm_mode_probed_add - add a mode to the specified output's probed mode list
+ * @output: output the new mode
+ * @mode: mode data
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ * 
+ * Add @mode to @output's mode list for later use.
+ */
+void drm_mode_probed_add(struct drm_output *output,
+                        struct drm_display_mode *mode)
+{
+       list_add(&mode->head, &output->probed_modes);
+}
+EXPORT_SYMBOL(drm_mode_probed_add);
+
+/**
+ * drm_mode_remove - remove and free a mode
+ * @output: output list to modify
+ * @mode: mode to remove
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ * 
+ * Remove @mode from @output's mode list, then free it.
+ */
+void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode)
+{
+       list_del(&mode->head);
+       kfree(mode);
+}
+EXPORT_SYMBOL(drm_mode_remove);
+
+/**
+ * drm_output_create - create a new output
+ * @dev: DRM device
+ * @funcs: callbacks for this output
+ * @name: user visible name of the output
+ *
+ * LOCKING:
+ * Caller must hold @dev's mode_config lock.
+ *
+ * Creates a new drm_output structure and adds it to @dev's mode_config
+ * structure.
+ *
+ * RETURNS:
+ * Pointer to the new output or NULL on error.
+ */
+struct drm_output *drm_output_create(struct drm_device *dev,
+                                    const struct drm_output_funcs *funcs,
+                                    int output_type)
+{
+       struct drm_output *output = NULL;
+
+       output = kzalloc(sizeof(struct drm_output), GFP_KERNEL);
+       if (!output)
+               return NULL;
+               
+       output->dev = dev;
+       output->funcs = funcs;
+       output->id = drm_idr_get(dev, output);
+       output->output_type = output_type;
+       output->output_type_id = 1; /* TODO */
+       output->subpixel_order = SubPixelUnknown;
+       INIT_LIST_HEAD(&output->user_modes);
+       INIT_LIST_HEAD(&output->probed_modes);
+       INIT_LIST_HEAD(&output->modes);
+       /* randr_output? */
+       /* output_set_monitor(output)? */
+       /* check for output_ignored(output)? */
+
+       mutex_lock(&dev->mode_config.mutex);
+       list_add_tail(&output->head, &dev->mode_config.output_list);
+       dev->mode_config.num_output++;
+
+       drm_output_attach_property(output, dev->mode_config.edid_property, 0);
+
+       drm_output_attach_property(output, dev->mode_config.dpms_property, 0);
+
+       mutex_unlock(&dev->mode_config.mutex);
+
+       return output;
+
+}
+EXPORT_SYMBOL(drm_output_create);
+
+/**
+ * drm_output_destroy - remove an output
+ * @output: output to remove
+ *
+ * LOCKING:
+ * Caller must hold @dev's mode_config lock.
+ *
+ * Call @output's cleanup function, then remove the output from the DRM
+ * mode_config after freeing @output's modes.
+ */
+void drm_output_destroy(struct drm_output *output)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_display_mode *mode, *t;
+
+       if (*output->funcs->cleanup)
+               (*output->funcs->cleanup)(output);
+
+       list_for_each_entry_safe(mode, t, &output->probed_modes, head)
+               drm_mode_remove(output, mode);
+
+       list_for_each_entry_safe(mode, t, &output->modes, head)
+               drm_mode_remove(output, mode);
+
+       list_for_each_entry_safe(mode, t, &output->user_modes, head)
+               drm_mode_remove(output, mode);
+
+       mutex_lock(&dev->mode_config.mutex);
+       drm_idr_put(dev, output->id);
+       list_del(&output->head);
+       mutex_unlock(&dev->mode_config.mutex);
+       kfree(output);
+}
+EXPORT_SYMBOL(drm_output_destroy);
+
+
+/**
+ * drm_mode_create - create a new display mode
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * None.
+ *
+ * Create a new drm_display_mode, give it an ID, and return it.
+ *
+ * RETURNS:
+ * Pointer to new mode on success, NULL on error.
+ */
+struct drm_display_mode *drm_mode_create(struct drm_device *dev)
+{
+       struct drm_display_mode *nmode;
+
+       nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
+       if (!nmode)
+               return NULL;
+
+       nmode->mode_id = drm_idr_get(dev, nmode);
+       return nmode;
+}
+EXPORT_SYMBOL(drm_mode_create);
+
+/**
+ * drm_mode_destroy - remove a mode
+ * @dev: DRM device
+ * @mode: mode to remove
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Free @mode's unique identifier, then free it.
+ */
+void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
+{
+       drm_idr_put(dev, mode->mode_id);
+
+       kfree(mode);
+}
+EXPORT_SYMBOL(drm_mode_destroy);
+
+static int drm_mode_create_standard_output_properties(struct drm_device *dev)
+{
+       int i;
+
+       /*
+        * Standard properties (apply to all outputs)
+        */
+       dev->mode_config.edid_property =
+               drm_property_create(dev, DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE,
+                                   "EDID", 0);
+
+       dev->mode_config.dpms_property =
+               drm_property_create(dev, DRM_MODE_PROP_ENUM, 
+                       "DPMS", ARRAY_SIZE(drm_dpms_enum_list));
+       for (i = 0; i < ARRAY_SIZE(drm_dpms_enum_list); i++)
+               drm_property_add_enum(dev->mode_config.dpms_property, i, drm_dpms_enum_list[i].type, drm_dpms_enum_list[i].name);
+
+       dev->mode_config.connector_type_property =
+               drm_property_create(dev, DRM_MODE_PROP_ENUM | DRM_MODE_PROP_IMMUTABLE,
+                       "Connector Type", ARRAY_SIZE(drm_conn_enum_list));
+       for (i = 0; i < ARRAY_SIZE(drm_conn_enum_list); i++)
+               drm_property_add_enum(dev->mode_config.connector_type_property, i, drm_conn_enum_list[i].type, drm_conn_enum_list[i].name);
+
+       dev->mode_config.connector_num_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE | DRM_MODE_PROP_IMMUTABLE,
+                       "Connector ID", 2);
+       dev->mode_config.connector_num_property->values[0] = 0;
+       dev->mode_config.connector_num_property->values[1] = 20;
+
+       /*
+        * TV specific properties
+        */
+       dev->mode_config.tv_left_margin_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE |
+                                   DRM_MODE_PROP_IMMUTABLE,
+                                   "left margin", 2);
+       dev->mode_config.tv_left_margin_property->values[0] = 0;
+       dev->mode_config.tv_left_margin_property->values[1] = 100;
+
+       dev->mode_config.tv_right_margin_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE |
+                                   DRM_MODE_PROP_IMMUTABLE,
+                                   "right margin", 2);
+       dev->mode_config.tv_right_margin_property->values[0] = 0;
+       dev->mode_config.tv_right_margin_property->values[1] = 100;
+
+       dev->mode_config.tv_top_margin_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE |
+                                   DRM_MODE_PROP_IMMUTABLE,
+                                   "top margin", 2);
+       dev->mode_config.tv_top_margin_property->values[0] = 0;
+       dev->mode_config.tv_top_margin_property->values[1] = 100;
+
+       dev->mode_config.tv_bottom_margin_property =
+               drm_property_create(dev, DRM_MODE_PROP_RANGE |
+                                   DRM_MODE_PROP_IMMUTABLE,
+                                   "bottom margin", 2);
+       dev->mode_config.tv_bottom_margin_property->values[0] = 0;
+       dev->mode_config.tv_bottom_margin_property->values[1] = 100;
+
+       return 0;
+}
+
+/**
+ * drm_mode_config_init - initialize DRM mode_configuration structure
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * None, should happen single threaded at init time.
+ *
+ * Initialize @dev's mode_config structure, used for tracking the graphics
+ * configuration of @dev.
+ */
+void drm_mode_config_init(struct drm_device *dev)
+{
+       mutex_init(&dev->mode_config.mutex);
+       INIT_LIST_HEAD(&dev->mode_config.fb_list);
+       INIT_LIST_HEAD(&dev->mode_config.crtc_list);
+       INIT_LIST_HEAD(&dev->mode_config.output_list);
+       INIT_LIST_HEAD(&dev->mode_config.property_list);
+       INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
+       idr_init(&dev->mode_config.crtc_idr);
+
+       drm_mode_create_standard_output_properties(dev);
+
+       /* Just to be sure */
+       dev->mode_config.num_fb = 0;
+       dev->mode_config.num_output = 0;
+       dev->mode_config.num_crtc = 0;
+       dev->mode_config.hotplug_counter = 0;
+}
+EXPORT_SYMBOL(drm_mode_config_init);
+
+/**
+ * drm_get_buffer_object - find the buffer object for a given handle
+ * @dev: DRM device
+ * @bo: pointer to caller's buffer_object pointer
+ * @handle: handle to lookup
+ *
+ * LOCKING:
+ * Must take @dev's struct_mutex to protect buffer object lookup.
+ *
+ * Given @handle, lookup the buffer object in @dev and put it in the caller's
+ * @bo pointer.
+ *
+ * RETURNS:
+ * Zero on success, -EINVAL if the handle couldn't be found.
+ */
+static int drm_get_buffer_object(struct drm_device *dev, struct drm_buffer_object **bo, unsigned long handle)
+{
+       struct drm_user_object *uo;
+       struct drm_hash_item *hash;
+       int ret;
+
+       *bo = NULL;
+
+       mutex_lock(&dev->struct_mutex);
+       ret = drm_ht_find_item(&dev->object_hash, handle, &hash);
+       if (ret) {
+               DRM_ERROR("Couldn't find handle.\n");
+               ret = -EINVAL;
+               goto out_err;
+       }
+
+       uo = drm_hash_entry(hash, struct drm_user_object, hash);
+       if (uo->type != drm_buffer_type) {
+               ret = -EINVAL;
+               goto out_err;
+       }
+       
+       *bo = drm_user_object_entry(uo, struct drm_buffer_object, base);
+       ret = 0;
+out_err:
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+}
+
+/**
+ * drm_pick_crtcs - pick crtcs for output devices
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ */
+static void drm_pick_crtcs (struct drm_device *dev)
+{
+       int c, o, assigned;
+       struct drm_output *output, *output_equal;
+       struct drm_crtc   *crtc;
+       struct drm_display_mode *des_mode = NULL, *modes, *modes_equal;
+       int found;
+
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+                       output->crtc = NULL;
+    
+               /* Don't hook up outputs that are disconnected ??
+                *
+                * This is debateable. Do we want fixed /dev/fbX or
+                * dynamic on hotplug (need mode code for that though) ?
+                *
+                * If we don't hook up outputs now, then we only create
+                * /dev/fbX for the output that's enabled, that's good as
+                * the users console will be on that output.
+                *
+                * If we do hook up outputs that are disconnected now, then
+                * the user may end up having to muck about with the fbcon
+                * map flags to assign his console to the enabled output. Ugh.
+                */
+               if (output->status != output_status_connected)
+                       continue;
+
+               if (list_empty(&output->modes))
+                       continue;
+
+               des_mode = NULL;
+               found = 0;
+               list_for_each_entry(des_mode, &output->modes, head) {
+                       if (des_mode->type & DRM_MODE_TYPE_PREFERRED) {
+                               found = 1;
+                               break;
+                       }
+               }
+
+               /* No preferred mode, let's just select the first available */
+               if (!found) {
+                       des_mode = NULL;
+                       list_for_each_entry(des_mode, &output->modes, head) {
+                               break;
+                       }
+               }
+
+               c = -1;
+               list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+                       assigned = 0;
+
+                       c++;
+                       if ((output->possible_crtcs & (1 << c)) == 0)
+                               continue;
+       
+                       list_for_each_entry(output_equal, &dev->mode_config.output_list, head) {
+                               if (output->id == output_equal->id)
+                                       continue;
+
+                               /* Find out if crtc has been assigned before */
+                               if (output_equal->crtc == crtc)
+                                       assigned = 1;
+                       }
+
+#if 1 /* continue for now */
+                       if (assigned)
+                               continue;
+#endif
+
+                       o = -1;
+                       list_for_each_entry(output_equal, &dev->mode_config.output_list, head) {
+                               o++;
+                               if (output->id == output_equal->id)
+                                       continue;
+
+                               list_for_each_entry(modes, &output->modes, head) {
+                                       list_for_each_entry(modes_equal, &output_equal->modes, head) {
+                                               if (drm_mode_equal (modes, modes_equal)) {
+                                                       if ((output->possible_clones & output_equal->possible_clones) && (output_equal->crtc == crtc)) {
+                                                               printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_output_name(output),output->possible_clones,drm_get_output_name(output_equal),output_equal->possible_clones);
+                                                               assigned = 0;
+                                                               goto clone;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+clone:
+                       /* crtc has been assigned skip it */
+                       if (assigned)
+                               continue;
+
+                       /* Found a CRTC to attach to, do it ! */
+                       output->crtc = crtc;
+                       output->crtc->desired_mode = des_mode;
+                       output->initial_x = 0;
+                       output->initial_y = 0;
+                       DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->mode_id, des_mode->name);
+                       break;
+               }
+       }
+}
+EXPORT_SYMBOL(drm_pick_crtcs);
+
+/**
+ * drm_initial_config - setup a sane initial output configuration
+ * @dev: DRM device
+ * @can_grow: this configuration is growable
+ *
+ * LOCKING:
+ * Called at init time, must take mode config lock.
+ *
+ * Scan the CRTCs and outputs and try to put together an initial setup.
+ * At the moment, this is a cloned configuration across all heads with
+ * a new framebuffer object as the backing store.
+ *
+ * RETURNS:
+ * Zero if everything went ok, nonzero otherwise.
+ */
+bool drm_initial_config(struct drm_device *dev, bool can_grow)
+{
+       struct drm_output *output;
+       struct drm_crtc *crtc;
+       int ret = false;
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       drm_crtc_probe_output_modes(dev, 2048, 2048);
+
+       drm_pick_crtcs(dev);
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+
+               /* can't setup the crtc if there's no assigned mode */
+               if (!crtc->desired_mode)
+                       continue;
+
+               /* Now setup the fbdev for attached crtcs */
+               dev->driver->fb_probe(dev, crtc);
+       }
+
+       /* This is a little screwy, as we've already walked the outputs 
+        * above, but it's a little bit of magic too. There's the potential
+        * for things not to get setup above if an existing device gets
+        * re-assigned thus confusing the hardware. By walking the outputs
+        * this fixes up their crtc's.
+        */
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+
+               /* can't setup the output if there's no assigned mode */
+               if (!output->crtc || !output->crtc->desired_mode)
+                       continue;
+
+               /* and needs an attached fb */
+               if (output->crtc->fb)
+                       drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0);
+       }
+
+       drm_disable_unused_functions(dev);
+
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+EXPORT_SYMBOL(drm_initial_config);
+
+/**
+ * drm_mode_config_cleanup - free up DRM mode_config info
+ * @dev: DRM device
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Free up all the outputs and CRTCs associated with this DRM device, then
+ * free up the framebuffers and associated buffer objects.
+ *
+ * FIXME: cleanup any dangling user buffer objects too
+ */
+void drm_mode_config_cleanup(struct drm_device *dev)
+{
+       struct drm_output *output, *ot;
+       struct drm_crtc *crtc, *ct;
+       struct drm_framebuffer *fb, *fbt;
+       struct drm_property *property, *pt;
+
+       list_for_each_entry_safe(output, ot, &dev->mode_config.output_list, head) {
+               drm_output_destroy(output);
+       }
+
+       list_for_each_entry_safe(property, pt, &dev->mode_config.property_list, head) {
+               drm_property_destroy(dev, property);
+       }
+
+       list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
+               /* there should only be bo of kernel type left */
+               if (fb->bo->type != drm_bo_type_kernel)
+                       drm_framebuffer_destroy(fb);
+               else
+                       dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, fb));
+       }
+
+       list_for_each_entry_safe(crtc, ct, &dev->mode_config.crtc_list, head) {
+               drm_crtc_destroy(crtc);
+       }
+
+}
+EXPORT_SYMBOL(drm_mode_config_cleanup);
+
+/**
+ * drm_crtc_set_config - set a new config from userspace
+ * @crtc: CRTC to setup
+ * @crtc_info: user provided configuration
+ * @new_mode: new mode to set
+ * @output_set: set of outputs for the new config
+ * @fb: new framebuffer
+ *
+ * LOCKING:
+ * Caller must hold mode config lock.
+ *
+ * Setup a new configuration, provided by the user in @crtc_info, and enable
+ * it.
+ *
+ * RETURNS:
+ * Zero. (FIXME)
+ */
+int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info, struct drm_display_mode *new_mode, struct drm_output **output_set, struct drm_framebuffer *fb)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_crtc **save_crtcs, *new_crtc;
+       bool save_enabled = crtc->enabled;
+       bool changed = false;
+       bool flip_or_move = false;
+       struct drm_output *output;
+       int count = 0, ro;
+
+       /* this is meant to be num_output not num_crtc */
+       save_crtcs = kzalloc(dev->mode_config.num_output * sizeof(struct drm_crtc *), GFP_KERNEL);
+       if (!save_crtcs)
+               return -ENOMEM;
+
+       /* We should be able to check here if the fb has the same properties
+        * and then just flip_or_move it */
+       if (crtc->fb != fb)
+               changed = true;
+
+       if (crtc_info->x != crtc->x || crtc_info->y != crtc->y)
+               flip_or_move = true;
+
+       if (new_mode && !drm_mode_equal(new_mode, &crtc->mode))
+               changed = true;
+
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+               save_crtcs[count++] = output->crtc;
+
+               if (output->crtc == crtc)
+                       new_crtc = NULL;
+               else
+                       new_crtc = output->crtc;
+
+               for (ro = 0; ro < crtc_info->count_outputs; ro++) {
+                       if (output_set[ro] == output)
+                               new_crtc = crtc;
+               }
+               if (new_crtc != output->crtc) {
+                       changed = true;
+                       output->crtc = new_crtc;
+               }
+       }
+
+       /* mode_set_base is not a required function */
+       if (flip_or_move && !crtc->funcs->mode_set_base)
+               changed = true;
+
+       if (changed) {
+               crtc->fb = fb;
+               crtc->enabled = (new_mode != NULL);
+               if (new_mode != NULL) {
+                       DRM_DEBUG("attempting to set mode from userspace\n");
+                       drm_mode_debug_printmodeline(dev, new_mode);
+                       if (!drm_crtc_set_mode(crtc, new_mode, crtc_info->x,
+                                              crtc_info->y)) {
+                               crtc->enabled = save_enabled;
+                               count = 0;
+                               list_for_each_entry(output, &dev->mode_config.output_list, head)
+                                       output->crtc = save_crtcs[count++];
+                               kfree(save_crtcs);
+                               return -EINVAL;
+                       }
+                       crtc->desired_x = crtc_info->x;
+                       crtc->desired_y = crtc_info->y;
+                       crtc->desired_mode = new_mode;
+               }
+               drm_disable_unused_functions(dev);
+       } else if (flip_or_move) {
+               crtc->funcs->mode_set_base(crtc, crtc_info->x, crtc_info->y);
+       }
+
+       kfree(save_crtcs);
+       return 0;
+}
+
+/**
+ * drm_hotplug_stage_two
+ * @dev DRM device
+ * @output hotpluged output
+ *
+ * LOCKING.
+ * Caller must hold mode config lock, function might grap struct lock.
+ *
+ * Stage two of a hotplug.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output,
+                         bool connected)
+{
+       int has_config = 0;
+
+       /* We might want to do something more here */
+       if (!connected) {
+               DRM_DEBUG("not connected\n");
+               dev->mode_config.hotplug_counter++;
+               return 0;
+       }
+
+       if (output->crtc && output->crtc->desired_mode) {
+               DRM_DEBUG("drm thinks that the output already has a config\n");
+               has_config = 1;
+       }
+
+       drm_crtc_probe_output_modes(dev, 2048, 2048);
+
+       if (!has_config)
+               drm_pick_crtcs(dev);
+
+       if (!output->crtc || !output->crtc->desired_mode) {
+               DRM_DEBUG("could not find a desired mode or crtc for output\n");
+               goto out_err;
+       }
+
+       /* We should realy check if there is a fb using this crtc */
+       if (!has_config)
+               dev->driver->fb_probe(dev, output->crtc);
+       else {
+               dev->driver->fb_resize(dev, output->crtc);
+
+               if (!drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0))
+                       DRM_ERROR("failed to set mode after hotplug\n");
+       }
+
+       drm_disable_unused_functions(dev);
+
+       dev->mode_config.hotplug_counter++;
+       return 0;
+
+out_err:
+       dev->mode_config.hotplug_counter++;
+       return 1;
+}
+EXPORT_SYMBOL(drm_hotplug_stage_two);
+
+int drm_mode_hotplug_ioctl(struct drm_device *dev,
+                          void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_hotplug *arg = data;
+
+       arg->counter = dev->mode_config.hotplug_counter;
+
+       return 0;
+}
+
+/**
+ * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo
+ * @out: drm_mode_modeinfo struct to return to the user
+ * @in: drm_display_mode to use
+ *
+ * LOCKING:
+ * None.
+ *
+ * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
+ * the user.
+ */
+void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out, struct drm_display_mode *in)
+{
+       out->clock = in->clock;
+       out->hdisplay = in->hdisplay;
+       out->hsync_start = in->hsync_start;
+       out->hsync_end = in->hsync_end;
+       out->htotal = in->htotal;
+       out->hskew = in->hskew;
+       out->vdisplay = in->vdisplay;
+       out->vsync_start = in->vsync_start;
+       out->vsync_end = in->vsync_end;
+       out->vtotal = in->vtotal;
+       out->vscan = in->vscan;
+       out->vrefresh = in->vrefresh;
+       out->flags = in->flags;
+       out->type = in->type;
+       strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
+       out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
+}
+
+/**
+ * drm_crtc_convert_to_umode - convert a modeinfo into a drm_display_mode
+ * @out: drm_display_mode to return to the user
+ * @in: drm_mode_modeinfo to use
+ *
+ * LOCKING:
+ * None.
+ *
+ * Convert a drmo_mode_modeinfo into a drm_display_mode structure to return to
+ * the caller.
+ */
+void drm_crtc_convert_umode(struct drm_display_mode *out, struct drm_mode_modeinfo *in)
+{
+       out->clock = in->clock;
+       out->hdisplay = in->hdisplay;
+       out->hsync_start = in->hsync_start;
+       out->hsync_end = in->hsync_end;
+       out->htotal = in->htotal;
+       out->hskew = in->hskew;
+       out->vdisplay = in->vdisplay;
+       out->vsync_start = in->vsync_start;
+       out->vsync_end = in->vsync_end;
+       out->vtotal = in->vtotal;
+       out->vscan = in->vscan;
+       out->vrefresh = in->vrefresh;
+       out->flags = in->flags;
+       out->type = in->type;
+       strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN);
+       out->name[DRM_DISPLAY_MODE_LEN-1] = 0;
+}
+       
+/**
+ * drm_mode_getresources - get graphics configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Construct a set of configuration description structures and return
+ * them to the user, including CRTC, output and framebuffer configuration.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_getresources(struct drm_device *dev,
+                         void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_card_res *card_res = data;
+       struct list_head *lh;
+       struct drm_framebuffer *fb;
+       struct drm_output *output;
+       struct drm_crtc *crtc;
+       int ret = 0;
+       int output_count = 0;
+       int crtc_count = 0;
+       int fb_count = 0;
+       int copied = 0;
+       uint32_t __user *fb_id;
+       uint32_t __user *crtc_id;
+       uint32_t __user *output_id;
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       list_for_each(lh, &dev->mode_config.fb_list)
+               fb_count++;
+
+       list_for_each(lh, &dev->mode_config.crtc_list)
+               crtc_count++;
+
+       list_for_each(lh, &dev->mode_config.output_list)
+               output_count++;
+
+       card_res->max_height = dev->mode_config.max_height;
+       card_res->min_height = dev->mode_config.min_height;
+       card_res->max_width = dev->mode_config.max_width;
+       card_res->min_width = dev->mode_config.min_width;
+
+       /* handle this in 4 parts */
+       /* FBs */
+       if (card_res->count_fbs >= fb_count) {
+               copied = 0;
+               fb_id = (uint32_t *)(unsigned long)card_res->fb_id_ptr;
+               list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
+                       if (put_user(fb->id, fb_id + copied)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+                       copied++;
+               }
+       }
+       card_res->count_fbs = fb_count;
+
+       /* CRTCs */
+       if (card_res->count_crtcs >= crtc_count) {
+               copied = 0;
+               crtc_id = (uint32_t *)(unsigned long)card_res->crtc_id_ptr;
+               list_for_each_entry(crtc, &dev->mode_config.crtc_list, head){
+                       DRM_DEBUG("CRTC ID is %d\n", crtc->id);
+                       if (put_user(crtc->id, crtc_id + copied)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+                       copied++;
+               }
+       }
+       card_res->count_crtcs = crtc_count;
+
+
+       /* Outputs */
+       if (card_res->count_outputs >= output_count) {
+               copied = 0;
+               output_id = (uint32_t *)(unsigned long)card_res->output_id_ptr;
+               list_for_each_entry(output, &dev->mode_config.output_list,
+                                   head) {
+                       DRM_DEBUG("OUTPUT ID is %d\n", output->id);
+                       if (put_user(output->id, output_id + copied)) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+                       copied++;
+               }
+       }
+       card_res->count_outputs = output_count;
+       
+       DRM_DEBUG("Counted %d %d\n", card_res->count_crtcs,
+                 card_res->count_outputs);
+
+out:   
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_getcrtc - get CRTC configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Construct a CRTC configuration structure to return to the user.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_getcrtc(struct drm_device *dev,
+                    void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_crtc *crtc_resp = data;
+       struct drm_crtc *crtc;
+       struct drm_output *output;
+       int ocount;
+       int ret = 0;
+
+       mutex_lock(&dev->mode_config.mutex);
+       crtc = idr_find(&dev->mode_config.crtc_idr, crtc_resp->crtc_id);
+       if (!crtc || (crtc->id != crtc_resp->crtc_id)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       crtc_resp->x = crtc->x;
+       crtc_resp->y = crtc->y;
+
+       if (crtc->fb)
+               crtc_resp->fb_id = crtc->fb->id;
+       else
+               crtc_resp->fb_id = 0;
+
+       crtc_resp->outputs = 0;
+       if (crtc->enabled) {
+
+               drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode);
+               crtc_resp->mode_valid = 1;
+               ocount = 0;
+               list_for_each_entry(output, &dev->mode_config.output_list, head) {
+                       if (output->crtc == crtc)
+                               crtc_resp->outputs |= 1 << (ocount++);
+               }
+               
+       } else {
+               crtc_resp->mode_valid = 0;
+       }
+
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_getoutput - get output configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Construct a output configuration structure to return to the user.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_getoutput(struct drm_device *dev,
+                      void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_get_output *out_resp = data;
+       struct drm_output *output;
+       struct drm_display_mode *mode;
+       int mode_count = 0;
+       int props_count = 0;
+       int ret = 0;
+       int copied = 0;
+       int i;
+       struct drm_mode_modeinfo u_mode;
+       struct drm_mode_modeinfo __user *mode_ptr;
+       uint32_t __user *prop_ptr;
+       uint64_t __user *prop_values;
+
+       memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo));
+
+       DRM_DEBUG("output id %d:\n", out_resp->output);
+
+       mutex_lock(&dev->mode_config.mutex);
+       output= idr_find(&dev->mode_config.crtc_idr, out_resp->output);
+       if (!output || (output->id != out_resp->output)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       list_for_each_entry(mode, &output->modes, head)
+               mode_count++;
+       
+       for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) {
+               if (output->property_ids[i] != 0) {
+                       props_count++;
+               }
+       }
+
+       if (out_resp->count_modes == 0) {
+               drm_crtc_probe_single_output_modes(output, dev->mode_config.max_width, dev->mode_config.max_height);
+       }
+
+       out_resp->output_type = output->output_type;
+       out_resp->output_type_id = output->output_type_id;
+       out_resp->mm_width = output->mm_width;
+       out_resp->mm_height = output->mm_height;
+       out_resp->subpixel = output->subpixel_order;
+       out_resp->connection = output->status;
+       if (output->crtc)
+               out_resp->crtc = output->crtc->id;
+       else
+               out_resp->crtc = 0;
+
+       out_resp->crtcs = output->possible_crtcs;
+       out_resp->clones = output->possible_clones;
+
+       if ((out_resp->count_modes >= mode_count) && mode_count) {
+               copied = 0;
+               mode_ptr = (struct drm_mode_modeinfo *)(unsigned long)out_resp->modes_ptr;
+               list_for_each_entry(mode, &output->modes, head) {
+                       drm_crtc_convert_to_umode(&u_mode, mode);
+                       if (copy_to_user(mode_ptr + copied,
+                                        &u_mode, sizeof(u_mode))) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+                       copied++;
+                       
+               }
+       }
+       out_resp->count_modes = mode_count;
+
+       if ((out_resp->count_props >= props_count) && props_count) {
+               copied = 0;
+               prop_ptr = (uint32_t *)(unsigned long)(out_resp->props_ptr);
+               prop_values = (uint64_t *)(unsigned long)(out_resp->prop_values_ptr);
+               for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) {
+                       if (output->property_ids[i] != 0) {
+                               if (put_user(output->property_ids[i], prop_ptr + copied)) {
+                                       ret = -EFAULT;
+                                       goto out;
+                               }
+
+                               if (put_user(output->property_values[i], prop_values + copied)) {
+                                       ret = -EFAULT;
+                                       goto out;
+                               }
+                               copied++;
+                       }
+               }
+       }
+       out_resp->count_props = props_count;
+
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_setcrtc - set CRTC configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Build a new CRTC configuration based on user request.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_setcrtc(struct drm_device *dev,
+                    void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_crtc *crtc_req = data;
+       struct drm_crtc *crtc, *crtcfb;
+       struct drm_output **output_set = NULL, *output;
+       struct drm_framebuffer *fb = NULL;
+       struct drm_display_mode *mode = NULL;
+       uint32_t __user *set_outputs_ptr;
+       int ret = 0;
+       int i;
+
+       mutex_lock(&dev->mode_config.mutex);
+       crtc = idr_find(&dev->mode_config.crtc_idr, crtc_req->crtc_id);
+       if (!crtc || (crtc->id != crtc_req->crtc_id)) {
+               DRM_DEBUG("Unknown CRTC ID %d\n", crtc_req->crtc_id);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (crtc_req->mode_valid) {
+               /* If we have a mode we need a framebuffer. */
+               /* If we pass -1, set the mode with the currently bound fb */
+               if (crtc_req->fb_id == -1) {
+                       list_for_each_entry(crtcfb, &dev->mode_config.crtc_list, head) {
+                               if (crtcfb == crtc) {
+                                       DRM_DEBUG("Using current fb for setmode\n");
+                                       fb = crtc->fb;          
+                               }
+                       }
+               } else {
+                       fb = idr_find(&dev->mode_config.crtc_idr, crtc_req->fb_id);
+                       if (!fb || (fb->id != crtc_req->fb_id)) {
+                               DRM_DEBUG("Unknown FB ID%d\n", crtc_req->fb_id);
+                               ret = -EINVAL;
+                               goto out;
+                       }
+               }
+
+               mode = drm_mode_create(dev);
+               drm_crtc_convert_umode(mode, &crtc_req->mode);
+               drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+       }
+
+       if (crtc_req->count_outputs == 0 && mode) {
+               DRM_DEBUG("Count outputs is 0 but mode set\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (crtc_req->count_outputs > 0 && !mode && !fb) {
+               DRM_DEBUG("Count outputs is %d but no mode or fb set\n", crtc_req->count_outputs);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (crtc_req->count_outputs > 0) {
+               u32 out_id;
+               /* Maybe we should check that count_outputs is a sensible value. */
+               output_set = kmalloc(crtc_req->count_outputs *
+                                    sizeof(struct drm_output *), GFP_KERNEL);
+               if (!output_set) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               for (i = 0; i < crtc_req->count_outputs; i++) {
+                       set_outputs_ptr = (uint32_t *)(unsigned long)crtc_req->set_outputs_ptr;
+                       if (get_user(out_id, &set_outputs_ptr[i])) {
+                               ret = -EFAULT;
+                               goto out;
+                       }
+
+                       output = idr_find(&dev->mode_config.crtc_idr, out_id);
+                       if (!output || (out_id != output->id)) {
+                               DRM_DEBUG("Output id %d unknown\n", out_id);
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
+                       output_set[i] = output;
+               }
+       }
+
+       ret = drm_crtc_set_config(crtc, crtc_req, mode, output_set, fb);
+
+out:
+       kfree(output_set);
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+int drm_mode_cursor_ioctl(struct drm_device *dev,
+                       void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_cursor *req = data;
+       struct drm_crtc *crtc;
+       struct drm_buffer_object *bo = NULL; /* must be set */
+       int ret = 0;
+
+       DRM_DEBUG("\n");
+
+       if (!req->flags) {
+               DRM_ERROR("no operation set\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&dev->mode_config.mutex);
+       crtc = idr_find(&dev->mode_config.crtc_idr, req->crtc);
+       if (!crtc || (crtc->id != req->crtc)) {
+               DRM_DEBUG("Unknown CRTC ID %d\n", req->crtc);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (req->flags & DRM_MODE_CURSOR_BO) {
+               /* Turn of the cursor if handle is 0 */
+               if (req->handle)
+                       ret = drm_get_buffer_object(dev, &bo, req->handle);
+
+               if (ret) {
+                       DRM_ERROR("invalid buffer id\n");
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               if (crtc->funcs->cursor_set) {
+                       ret = crtc->funcs->cursor_set(crtc, bo, req->width, req->height);
+               } else {
+                       DRM_ERROR("crtc does not support cursor\n");
+                       ret = -EFAULT;
+                       goto out;
+               }
+       }
+
+       if (req->flags & DRM_MODE_CURSOR_MOVE) {
+               if (crtc->funcs->cursor_move) {
+                       ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
+               } else {
+                       DRM_ERROR("crtc does not support cursor\n");
+                       ret = -EFAULT;
+                       goto out;
+               }
+       }
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_addfb - add an FB to the graphics configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Add a new FB to the specified CRTC, given a user request.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_addfb(struct drm_device *dev,
+                  void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_fb_cmd *r = data;
+       struct drm_mode_config *config = &dev->mode_config;
+       struct drm_framebuffer *fb;
+       struct drm_buffer_object *bo;
+       int ret = 0;
+
+       if ((config->min_width > r->width) || (r->width > config->max_width)) {
+               DRM_ERROR("mode new framebuffer width not within limits\n");
+               return -EINVAL;
+       }
+       if ((config->min_height > r->height) || (r->height > config->max_height)) {
+               DRM_ERROR("mode new framebuffer height not within limits\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&dev->mode_config.mutex);
+       /* TODO check limits are okay */
+       ret = drm_get_buffer_object(dev, &bo, r->handle);
+       if (ret || !bo) {
+               DRM_ERROR("BO handle not valid\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* TODO check buffer is sufficently large */
+       /* TODO setup destructor callback */
+
+       fb = drm_framebuffer_create(dev);
+       if (!fb) {
+               DRM_ERROR("could not create framebuffer\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       fb->width = r->width;
+       fb->height = r->height;
+       fb->pitch = r->pitch;
+       fb->bits_per_pixel = r->bpp;
+       fb->depth = r->depth;
+       fb->bo = bo;
+
+       r->buffer_id = fb->id;
+
+       list_add(&fb->filp_head, &file_priv->fbs);
+
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_rmfb - remove an FB from the configuration
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Remove the FB specified by the user.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_rmfb(struct drm_device *dev,
+                  void *data, struct drm_file *file_priv)
+{
+       struct drm_framebuffer *fb = 0;
+       struct drm_framebuffer *fbl = 0;
+       uint32_t *id = data;
+       int ret = 0;
+       int found = 0;
+
+       mutex_lock(&dev->mode_config.mutex);
+       fb = idr_find(&dev->mode_config.crtc_idr, *id);
+       /* TODO check that we realy get a framebuffer back. */
+       if (!fb || (*id != fb->id)) {
+               DRM_ERROR("mode invalid framebuffer id\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       list_for_each_entry(fbl, &file_priv->fbs, filp_head)
+               if (fb == fbl)
+                       found = 1;
+
+       if (!found) {
+               DRM_ERROR("tried to remove a fb that we didn't own\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* TODO release all crtc connected to the framebuffer */
+       /* TODO unhock the destructor from the buffer object */
+
+       if (fb->bo->type == drm_bo_type_kernel)
+               DRM_ERROR("the bo type should not be of kernel type\n");
+
+       list_del(&fb->filp_head);
+       drm_framebuffer_destroy(fb);
+
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_mode_getfb - get FB info
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * LOCKING:
+ * Caller? (FIXME)
+ *
+ * Lookup the FB given its ID and return info about it.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_getfb(struct drm_device *dev,
+                  void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_fb_cmd *r = data;
+       struct drm_framebuffer *fb;
+       int ret = 0;
+
+       mutex_lock(&dev->mode_config.mutex);
+       fb = idr_find(&dev->mode_config.crtc_idr, r->buffer_id);
+       if (!fb || (r->buffer_id != fb->id)) {
+               DRM_ERROR("invalid framebuffer id\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       r->height = fb->height;
+       r->width = fb->width;
+       r->depth = fb->depth;
+       r->bpp = fb->bits_per_pixel;
+       r->handle = fb->bo->base.hash.key;
+       r->pitch = fb->pitch;
+
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+/**
+ * drm_fb_release - remove and free the FBs on this file
+ * @filp: file * from the ioctl
+ *
+ * LOCKING:
+ * Takes mode config lock.
+ *
+ * Destroy all the FBs associated with @filp.
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+void drm_fb_release(struct file *filp)
+{
+       struct drm_file *priv = filp->private_data;
+       struct drm_device *dev = priv->minor->dev;
+       struct drm_framebuffer *fb, *tfb;
+
+       mutex_lock(&dev->mode_config.mutex);
+       list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
+               list_del(&fb->filp_head);
+               if (fb->bo->type == drm_bo_type_kernel)
+                       DRM_ERROR("the bo type should not be of kernel_type, the kernel will probably explode, why Dave\n");
+
+               drm_framebuffer_destroy(fb);
+       }
+       mutex_unlock(&dev->mode_config.mutex);
+}
+
+/*
+ *
+ */
+
+static int drm_mode_attachmode(struct drm_device *dev,
+                              struct drm_output *output,
+                              struct drm_display_mode *mode)
+{
+       int ret = 0;
+
+       list_add_tail(&mode->head, &output->user_modes);
+       return ret;
+}
+
+int drm_mode_attachmode_crtc(struct drm_device *dev, struct drm_crtc *crtc,
+                            struct drm_display_mode *mode)
+{
+       struct drm_output *output;
+       int ret = 0;
+       struct drm_display_mode *dup_mode;
+       int need_dup = 0;
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+               if (output->crtc == crtc) {
+                       if (need_dup)
+                               dup_mode = drm_mode_duplicate(dev, mode);
+                       else
+                               dup_mode = mode;
+                       ret = drm_mode_attachmode(dev, output, dup_mode); 
+                       if (ret)
+                               return ret;
+                       need_dup = 1;
+               }
+       }
+       return 0;
+}
+EXPORT_SYMBOL(drm_mode_attachmode_crtc);
+
+static int drm_mode_detachmode(struct drm_device *dev,
+                              struct drm_output *output,
+                              struct drm_display_mode *mode)
+{
+       int found = 0;
+       int ret = 0;
+       struct drm_display_mode *match_mode, *t;
+
+       list_for_each_entry_safe(match_mode, t, &output->user_modes, head) {
+               if (drm_mode_equal(match_mode, mode)) {
+                       list_del(&match_mode->head);
+                       drm_mode_destroy(dev, match_mode);
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found)
+               ret = -EINVAL;
+
+       return ret;
+}
+
+int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode)
+{
+       struct drm_output *output;
+
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+               drm_mode_detachmode(dev, output, mode);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(drm_mode_detachmode_crtc);
+
+/**
+ * drm_fb_attachmode - Attach a user mode to an output
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * This attaches a user specified mode to an output.
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_attachmode_ioctl(struct drm_device *dev,
+                             void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_mode_cmd *mode_cmd = data;
+       struct drm_output *output;
+       struct drm_display_mode *mode;
+       struct drm_mode_modeinfo *umode = &mode_cmd->mode;
+       int ret = 0;
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       output = idr_find(&dev->mode_config.crtc_idr, mode_cmd->output_id);
+       if (!output || (output->id != mode_cmd->output_id)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       mode = drm_mode_create(dev);
+       if (!mode) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       
+       drm_crtc_convert_umode(mode, umode);
+
+       ret = drm_mode_attachmode(dev, output, mode);
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+
+/**
+ * drm_fb_detachmode - Detach a user specified mode from an output
+ * @inode: inode from the ioctl
+ * @filp: file * from the ioctl
+ * @cmd: cmd from ioctl
+ * @arg: arg from ioctl
+ *
+ * Called by the user via ioctl.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int drm_mode_detachmode_ioctl(struct drm_device *dev,
+                             void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_mode_cmd *mode_cmd = data;
+       struct drm_output *output;
+       struct drm_display_mode mode;
+       struct drm_mode_modeinfo *umode = &mode_cmd->mode;
+       int ret = 0;
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       output = idr_find(&dev->mode_config.crtc_idr, mode_cmd->output_id);
+       if (!output || (output->id != mode_cmd->output_id)) {
+               ret = -EINVAL;
+               goto out;
+       }
+       
+       drm_crtc_convert_umode(&mode, umode);
+       ret = drm_mode_detachmode(dev, output, &mode);
+out:          
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+struct drm_property *drm_property_create(struct drm_device *dev, int flags,
+                                        const char *name, int num_values)
+{
+       struct drm_property *property = NULL;
+
+       property = kzalloc(sizeof(struct drm_property), GFP_KERNEL);
+       if (!property)
+               return NULL;
+
+       if (num_values) {
+               property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL);
+               if (!property->values)
+                       goto fail;
+       }
+
+       property->id = drm_idr_get(dev, property);
+       property->flags = flags;
+       property->num_values = num_values;
+       INIT_LIST_HEAD(&property->enum_blob_list);
+
+       if (name)
+               strncpy(property->name, name, DRM_PROP_NAME_LEN);
+
+       list_add_tail(&property->head, &dev->mode_config.property_list);
+       return property;
+fail:
+       kfree(property);
+       return NULL;
+}
+EXPORT_SYMBOL(drm_property_create);
+
+int drm_property_add_enum(struct drm_property *property, int index,
+                         uint64_t value, const char *name)
+{
+       struct drm_property_enum *prop_enum;
+
+       if (!(property->flags & DRM_MODE_PROP_ENUM))
+               return -EINVAL;
+
+       if (!list_empty(&property->enum_blob_list)) {
+               list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
+                       if (prop_enum->value == value) {
+                               strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 
+                               prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
+                               return 0;
+                       }
+               }
+       }
+
+       prop_enum = kzalloc(sizeof(struct drm_property_enum), GFP_KERNEL);
+       if (!prop_enum)
+               return -ENOMEM;
+
+       strncpy(prop_enum->name, name, DRM_PROP_NAME_LEN); 
+       prop_enum->name[DRM_PROP_NAME_LEN-1] = '\0';
+       prop_enum->value = value;
+
+       property->values[index] = value;
+       list_add_tail(&prop_enum->head, &property->enum_blob_list);
+       return 0;
+}
+EXPORT_SYMBOL(drm_property_add_enum);
+
+void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
+{
+       struct drm_property_enum *prop_enum, *pt;
+
+       list_for_each_entry_safe(prop_enum, pt, &property->enum_blob_list, head) {
+               list_del(&prop_enum->head);
+               kfree(prop_enum);
+       }
+
+       if (property->num_values)
+               kfree(property->values);
+       drm_idr_put(dev, property->id);
+       list_del(&property->head);
+       kfree(property);        
+}
+EXPORT_SYMBOL(drm_property_destroy);
+
+int drm_output_attach_property(struct drm_output *output,
+                              struct drm_property *property, uint64_t init_val)
+{
+       int i;
+
+       for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) {
+               if (output->property_ids[i] == 0) {
+                       output->property_ids[i] = property->id;
+                       output->property_values[i] = init_val;
+                       break;
+               }
+       }
+
+       if (i == DRM_OUTPUT_MAX_PROPERTY)
+               return -EINVAL;
+       return 0;
+}
+EXPORT_SYMBOL(drm_output_attach_property);
+
+int drm_output_property_set_value(struct drm_output *output,
+                                 struct drm_property *property, uint64_t value)
+{
+       int i;
+
+       for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) {
+               if (output->property_ids[i] == property->id) {
+                       output->property_values[i] = value;
+                       break;
+               }
+       }
+
+       if (i == DRM_OUTPUT_MAX_PROPERTY)
+               return -EINVAL;
+       return 0;
+}
+EXPORT_SYMBOL(drm_output_property_set_value);
+
+int drm_mode_getproperty_ioctl(struct drm_device *dev,
+                              void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_get_property *out_resp = data;
+       struct drm_property *property;
+       int enum_count = 0;
+       int blob_count = 0;
+       int value_count = 0;
+       int ret = 0, i;
+       int copied;
+       struct drm_property_enum *prop_enum;
+       struct drm_mode_property_enum __user *enum_ptr;
+       struct drm_property_blob *prop_blob;
+       uint32_t *blob_id_ptr;
+       uint64_t __user *values_ptr;
+       uint32_t __user *blob_length_ptr;
+
+       mutex_lock(&dev->mode_config.mutex);
+       property = idr_find(&dev->mode_config.crtc_idr, out_resp->prop_id);
+       if (!property || (property->id != out_resp->prop_id)) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       if (property->flags & DRM_MODE_PROP_ENUM) {
+               list_for_each_entry(prop_enum, &property->enum_blob_list, head)
+                       enum_count++;
+       } else if (property->flags & DRM_MODE_PROP_BLOB) {
+               list_for_each_entry(prop_blob, &property->enum_blob_list, head)
+                       blob_count++;
+       }
+
+       value_count = property->num_values;
+
+       strncpy(out_resp->name, property->name, DRM_PROP_NAME_LEN);
+       out_resp->name[DRM_PROP_NAME_LEN-1] = 0;
+       out_resp->flags = property->flags;
+
+       if ((out_resp->count_values >= value_count) && value_count) {
+               values_ptr = (uint64_t *)(unsigned long)out_resp->values_ptr;
+               for (i = 0; i < value_count; i++) {
+                       if (copy_to_user(values_ptr + i, &property->values[i], sizeof(uint64_t))) {
+                               ret = -EFAULT;
+                               goto done;
+                       }
+               }
+       }
+       out_resp->count_values = value_count;
+
+       if (property->flags & DRM_MODE_PROP_ENUM) {
+
+               if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
+                       copied = 0;
+                       enum_ptr = (struct drm_mode_property_enum *)(unsigned long)out_resp->enum_blob_ptr;
+                       list_for_each_entry(prop_enum, &property->enum_blob_list, head) {
+                               
+                               if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) {
+                                       ret = -EFAULT;
+                                       goto done;
+                               }
+                               
+                               if (copy_to_user(&enum_ptr[copied].name,
+                                                &prop_enum->name, DRM_PROP_NAME_LEN)) {
+                                       ret = -EFAULT;
+                                       goto done;
+                               }
+                               copied++;
+                       }
+               }
+               out_resp->count_enum_blobs = enum_count;
+       }
+
+       if (property->flags & DRM_MODE_PROP_BLOB) {
+               if ((out_resp->count_enum_blobs >= blob_count) && blob_count) {
+                       copied = 0;
+                       blob_id_ptr = (uint32_t *)(unsigned long)out_resp->enum_blob_ptr;
+                       blob_length_ptr = (uint32_t *)(unsigned long)out_resp->values_ptr;
+                       
+                       list_for_each_entry(prop_blob, &property->enum_blob_list, head) {
+                               if (put_user(prop_blob->id, blob_id_ptr + copied)) {
+                                       ret = -EFAULT;
+                                       goto done;
+                               }
+                               
+                               if (put_user(prop_blob->length, blob_length_ptr + copied)) {
+                                       ret = -EFAULT;
+                                       goto done;
+                               }
+                               
+                               copied++;
+                       }
+               }
+               out_resp->count_enum_blobs = enum_count;
+       }
+done:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev, int length,
+                                                         void *data)
+{
+       struct drm_property_blob *blob;
+
+       if (!length || !data)
+               return NULL;
+
+       blob = kzalloc(sizeof(struct drm_property_blob)+length, GFP_KERNEL);
+       if (!blob)
+               return NULL;
+
+       blob->data = (void *)((char *)blob + sizeof(struct drm_property_blob));
+       blob->length = length;
+
+       memcpy(blob->data, data, length);
+
+       blob->id = drm_idr_get(dev, blob);
+       
+       list_add_tail(&blob->head, &dev->mode_config.property_blob_list);
+       return blob;
+}
+
+static void drm_property_destroy_blob(struct drm_device *dev,
+                              struct drm_property_blob *blob)
+{
+       drm_idr_put(dev, blob->id);
+       list_del(&blob->head);
+       kfree(blob);
+}
+
+int drm_mode_getblob_ioctl(struct drm_device *dev,
+                          void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_get_blob *out_resp = data;
+       struct drm_property_blob *blob;
+       int ret = 0;
+       void *blob_ptr;
+
+       mutex_lock(&dev->mode_config.mutex);
+       
+       blob = idr_find(&dev->mode_config.crtc_idr, out_resp->blob_id);
+       if (!blob || (blob->id != out_resp->blob_id)) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       if (out_resp->length == blob->length) {
+               blob_ptr = (void *)(unsigned long)out_resp->data;
+               if (copy_to_user(blob_ptr, blob->data, blob->length)){
+                       ret = -EFAULT;
+                       goto done;
+               }
+       }
+       out_resp->length = blob->length;
+
+done:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
+int drm_mode_output_update_edid_property(struct drm_output *output, struct edid *edid)
+{
+       struct drm_device *dev = output->dev;
+       int ret = 0;
+       if (output->edid_blob_ptr)
+               drm_property_destroy_blob(dev, output->edid_blob_ptr);
+
+       output->edid_blob_ptr = drm_property_create_blob(output->dev, 128, edid);
+       
+       ret = drm_output_property_set_value(output, dev->mode_config.edid_property, output->edid_blob_ptr->id);
+       return ret;
+}
+EXPORT_SYMBOL(drm_mode_output_update_edid_property);
+
+int drm_mode_output_property_set_ioctl(struct drm_device *dev,
+                                      void *data, struct drm_file *file_priv)
+{
+       struct drm_mode_output_set_property *out_resp = data;
+       struct drm_property *property;
+       struct drm_output *output;
+       int ret = -EINVAL;
+       int i;
+
+       mutex_lock(&dev->mode_config.mutex);
+       output = idr_find(&dev->mode_config.crtc_idr, out_resp->output_id);
+       if (!output || (output->id != out_resp->output_id)) {
+               goto out;
+       }
+
+       for (i = 0; i < DRM_OUTPUT_MAX_PROPERTY; i++) {
+               if (output->property_ids[i] == out_resp->prop_id)
+                       break;
+       }
+
+       if (i == DRM_OUTPUT_MAX_PROPERTY) {
+               goto out;
+       }
+       
+       property = idr_find(&dev->mode_config.crtc_idr, out_resp->prop_id);
+       if (!property || (property->id != out_resp->prop_id)) {
+               goto out;
+       }
+
+       if (property->flags & DRM_MODE_PROP_IMMUTABLE)
+               goto out;
+
+       if (property->flags & DRM_MODE_PROP_RANGE) {
+               if (out_resp->value < property->values[0])
+                       goto out;
+
+               if (out_resp->value > property->values[1])
+                       goto out;
+       } else {
+               int found = 0;
+               for (i = 0; i < property->num_values; i++) {
+                       if (property->values[i] == out_resp->value) {
+                               found = 1;
+                               break;
+                       }
+               }
+               if (!found) {
+                       goto out;
+               }
+       }
+
+       if (output->funcs->set_property)
+               ret = output->funcs->set_property(output, property, out_resp->value);
+
+out:
+       mutex_unlock(&dev->mode_config.mutex);
+       return ret;
+}
+
diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h
new file mode 100644 (file)
index 0000000..bbeab60
--- /dev/null
@@ -0,0 +1,666 @@
+/*
+ * Copyright Â© 2006 Keith Packard
+ * Copyright Â© 2007 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ */
+#ifndef __DRM_CRTC_H__
+#define __DRM_CRTC_H__
+
+#include <linux/i2c.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/idr.h>
+
+#include <linux/fb.h>
+
+struct drm_device;
+
+/*
+ * Note on terminology:  here, for brevity and convenience, we refer to output
+ * control chips as 'CRTCs'.  They can control any type of output, VGA, LVDS,
+ * DVI, etc.  And 'screen' refers to the whole of the visible display, which
+ * may span multiple monitors (and therefore multiple CRTC and output
+ * structures).
+ */
+
+enum drm_mode_status {
+    MODE_OK    = 0,    /* Mode OK */
+    MODE_HSYNC,                /* hsync out of range */
+    MODE_VSYNC,                /* vsync out of range */
+    MODE_H_ILLEGAL,    /* mode has illegal horizontal timings */
+    MODE_V_ILLEGAL,    /* mode has illegal horizontal timings */
+    MODE_BAD_WIDTH,    /* requires an unsupported linepitch */
+    MODE_NOMODE,       /* no mode with a maching name */
+    MODE_NO_INTERLACE, /* interlaced mode not supported */
+    MODE_NO_DBLESCAN,  /* doublescan mode not supported */
+    MODE_NO_VSCAN,     /* multiscan mode not supported */
+    MODE_MEM,          /* insufficient video memory */
+    MODE_VIRTUAL_X,    /* mode width too large for specified virtual size */
+    MODE_VIRTUAL_Y,    /* mode height too large for specified virtual size */
+    MODE_MEM_VIRT,     /* insufficient video memory given virtual size */
+    MODE_NOCLOCK,      /* no fixed clock available */
+    MODE_CLOCK_HIGH,   /* clock required is too high */
+    MODE_CLOCK_LOW,    /* clock required is too low */
+    MODE_CLOCK_RANGE,  /* clock/mode isn't in a ClockRange */
+    MODE_BAD_HVALUE,   /* horizontal timing was out of range */
+    MODE_BAD_VVALUE,   /* vertical timing was out of range */
+    MODE_BAD_VSCAN,    /* VScan value out of range */
+    MODE_HSYNC_NARROW, /* horizontal sync too narrow */
+    MODE_HSYNC_WIDE,   /* horizontal sync too wide */
+    MODE_HBLANK_NARROW,        /* horizontal blanking too narrow */
+    MODE_HBLANK_WIDE,  /* horizontal blanking too wide */
+    MODE_VSYNC_NARROW, /* vertical sync too narrow */
+    MODE_VSYNC_WIDE,   /* vertical sync too wide */
+    MODE_VBLANK_NARROW,        /* vertical blanking too narrow */
+    MODE_VBLANK_WIDE,  /* vertical blanking too wide */
+    MODE_PANEL,         /* exceeds panel dimensions */
+    MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */
+    MODE_ONE_WIDTH,     /* only one width is supported */
+    MODE_ONE_HEIGHT,    /* only one height is supported */
+    MODE_ONE_SIZE,      /* only one resolution is supported */
+    MODE_NO_REDUCED,    /* monitor doesn't accept reduced blanking */
+    MODE_UNVERIFIED = -3, /* mode needs to reverified */
+    MODE_BAD = -2,     /* unspecified reason */
+    MODE_ERROR = -1    /* error condition */
+};
+
+#define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \
+                                   DRM_MODE_TYPE_CRTC_C)
+
+#define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \
+       .name = nm, .status = 0, .type = (t), .clock = (c), \
+       .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \
+       .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \
+       .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \
+       .vscan = (vs), .flags = (f), .vrefresh = 0
+
+struct drm_display_mode {
+       /* Header */
+       struct list_head head;
+       char name[DRM_DISPLAY_MODE_LEN];
+       int mode_id;
+       int output_count;
+       enum drm_mode_status status;
+       int type;
+
+       /* Proposed mode values */
+       int clock;
+       int hdisplay;
+       int hsync_start;
+       int hsync_end;
+       int htotal;
+       int hskew;
+       int vdisplay;
+       int vsync_start;
+       int vsync_end;
+       int vtotal;
+       int vscan;
+       unsigned int flags;
+
+       /* Actual mode we give to hw */
+       int clock_index;
+       int synth_clock;
+       int crtc_hdisplay;
+       int crtc_hblank_start;
+       int crtc_hblank_end;
+       int crtc_hsync_start;
+       int crtc_hsync_end;
+       int crtc_htotal;
+       int crtc_hskew;
+       int crtc_vdisplay;
+       int crtc_vblank_start;
+       int crtc_vblank_end;
+       int crtc_vsync_start;
+       int crtc_vsync_end;
+       int crtc_vtotal;
+       int crtc_hadjusted;
+       int crtc_vadjusted;
+
+       /* Driver private mode info */
+       int private_size;
+       int *private;
+       int private_flags;
+
+       int vrefresh;
+       float hsync;
+};
+
+/* Video mode flags */
+#define V_PHSYNC       (1<<0)
+#define V_NHSYNC       (1<<1)
+#define V_PVSYNC       (1<<2)
+#define V_NVSYNC       (1<<3)
+#define V_INTERLACE    (1<<4)
+#define V_DBLSCAN      (1<<5)
+#define V_CSYNC                (1<<6)
+#define V_PCSYNC       (1<<7)
+#define V_NCSYNC       (1<<8)
+#define V_HSKEW                (1<<9) /* hskew provided */
+#define V_BCAST                (1<<10)
+#define V_PIXMUX       (1<<11)
+#define V_DBLCLK       (1<<12)
+#define V_CLKDIV2      (1<<13)
+
+#define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */
+
+#define DPMSModeOn 0
+#define DPMSModeStandby 1
+#define DPMSModeSuspend 2
+#define DPMSModeOff 3
+
+#define ConnectorUnknown 0
+#define ConnectorVGA 1
+#define ConnectorDVII 2
+#define ConnectorDVID 3
+#define ConnectorDVIA 4
+#define ConnectorComposite 5
+#define ConnectorSVIDEO 6
+#define ConnectorLVDS 7
+#define ConnectorComponent 8
+#define Connector9PinDIN 9
+#define ConnectorDisplayPort 10
+#define ConnectorHDMIA 11
+#define ConnectorHDMIB 12
+
+enum drm_output_status {
+       output_status_connected = 1,
+       output_status_disconnected = 2,
+       output_status_unknown = 3,
+};
+
+enum subpixel_order {
+       SubPixelUnknown = 0,
+       SubPixelHorizontalRGB,
+       SubPixelHorizontalBGR,
+       SubPixelVerticalRGB,
+       SubPixelVerticalBGR,
+       SubPixelNone,
+};
+
+/*
+ * Describes a given display (e.g. CRT or flat panel) and its limitations.
+ */
+struct drm_display_info {
+       char name[DRM_DISPLAY_INFO_LEN];
+       /* Input info */
+       bool serration_vsync;
+       bool sync_on_green;
+       bool composite_sync;
+       bool separate_syncs;
+       bool blank_to_black;
+       unsigned char video_level;
+       bool digital;
+       /* Physical size */
+        unsigned int width_mm;
+       unsigned int height_mm;
+
+       /* Display parameters */
+       unsigned char gamma; /* FIXME: storage format */
+       bool gtf_supported;
+       bool standard_color;
+       enum {
+               monochrome,
+               rgb,
+               other,
+               unknown,
+       } display_type;
+       bool active_off_supported;
+       bool suspend_supported;
+       bool standby_supported;
+
+       /* Color info FIXME: storage format */
+       unsigned short redx, redy;
+       unsigned short greenx, greeny;
+       unsigned short bluex, bluey;
+       unsigned short whitex, whitey;
+
+       /* Clock limits FIXME: storage format */
+       unsigned int min_vfreq, max_vfreq;
+       unsigned int min_hfreq, max_hfreq;
+       unsigned int pixel_clock;
+
+       /* White point indices FIXME: storage format */
+       unsigned int wpx1, wpy1;
+       unsigned int wpgamma1;
+       unsigned int wpx2, wpy2;
+       unsigned int wpgamma2;
+
+       /* Preferred mode (if any) */
+       struct drm_display_mode *preferred_mode;
+       char *raw_edid; /* if any */
+};
+
+struct drm_framebuffer {
+       struct drm_device *dev;
+       struct list_head head;
+       int id; /* idr assigned */
+       unsigned int pitch;
+       unsigned int width;
+       unsigned int height;
+       /* depth can be 15 or 16 */
+       unsigned int depth;
+       int bits_per_pixel;
+       int flags;
+       struct drm_buffer_object *bo;
+       void *fbdev;
+       u32 pseudo_palette[17];
+       struct drm_bo_kmap_obj kmap;
+       struct list_head filp_head;
+};
+
+struct drm_property_blob {
+       struct list_head head;
+       unsigned int length;
+       unsigned int id;
+       void *data;
+};
+
+struct drm_property_enum {
+       uint64_t value;
+       struct list_head head;
+       char name[DRM_PROP_NAME_LEN];
+};
+
+struct drm_property {
+       struct list_head head;
+       int id; /* idr assigned */
+       uint32_t flags;
+       char name[DRM_PROP_NAME_LEN];
+       uint32_t num_values;
+       uint64_t *values;
+
+       struct list_head enum_blob_list;
+};
+
+struct drm_crtc;
+struct drm_output;
+
+/**
+ * drm_crtc_funcs - control CRTCs for a given device
+ * @dpms: control display power levels
+ * @save: save CRTC state
+ * @resore: restore CRTC state
+ * @lock: lock the CRTC
+ * @unlock: unlock the CRTC
+ * @shadow_allocate: allocate shadow pixmap
+ * @shadow_create: create shadow pixmap for rotation support
+ * @shadow_destroy: free shadow pixmap
+ * @mode_fixup: fixup proposed mode
+ * @mode_set: set the desired mode on the CRTC
+ * @gamma_set: specify color ramp for CRTC
+ * @cleanup: cleanup driver private state prior to close
+ *
+ * The drm_crtc_funcs structure is the central CRTC management structure
+ * in the DRM.  Each CRTC controls one or more outputs (note that the name
+ * CRTC is simply historical, a CRTC may control LVDS, VGA, DVI, TV out, etc.
+ * outputs, not just CRTs).
+ *
+ * Each driver is responsible for filling out this structure at startup time,
+ * in addition to providing other modesetting features, like i2c and DDC
+ * bus accessors.
+ */
+struct drm_crtc_funcs {
+       /*
+        * Control power levels on the CRTC.  If the mode passed in is
+        * unsupported, the provider must use the next lowest power level.
+        */
+       void (*dpms)(struct drm_crtc *crtc, int mode);
+
+       /* JJJ:  Are these needed? */
+       /* Save CRTC state */
+       void (*save)(struct drm_crtc *crtc); /* suspend? */
+       /* Restore CRTC state */
+       void (*restore)(struct drm_crtc *crtc); /* resume? */
+       bool (*lock)(struct drm_crtc *crtc);
+       void (*unlock)(struct drm_crtc *crtc);
+
+       void (*prepare)(struct drm_crtc *crtc);
+       void (*commit)(struct drm_crtc *crtc);
+
+       /* Provider can fixup or change mode timings before modeset occurs */
+       bool (*mode_fixup)(struct drm_crtc *crtc,
+                          struct drm_display_mode *mode,
+                          struct drm_display_mode *adjusted_mode);
+       /* Actually set the mode */
+       void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                        struct drm_display_mode *adjusted_mode, int x, int y);
+
+       /* Move the crtc on the current fb to the given position *optional* */
+       void (*mode_set_base)(struct drm_crtc *crtc, int x, int y);
+
+       /* cursor controls */
+       int (*cursor_set)(struct drm_crtc *crtc, struct drm_buffer_object *bo,
+                         uint32_t width, uint32_t height);
+       int (*cursor_move)(struct drm_crtc *crtc, int x, int y);
+
+       /* Set gamma on the CRTC */
+       void (*gamma_set)(struct drm_crtc *crtc, u16 r, u16 g, u16 b,
+                         int regno);
+       /* Driver cleanup routine */
+       void (*cleanup)(struct drm_crtc *crtc);
+};
+
+/**
+ * drm_crtc - central CRTC control structure
+ * @enabled: is this CRTC enabled?
+ * @x: x position on screen
+ * @y: y position on screen
+ * @desired_mode: new desired mode
+ * @desired_x: desired x for desired_mode
+ * @desired_y: desired y for desired_mode
+ * @funcs: CRTC control functions
+ * @driver_private: arbitrary driver data
+ *
+ * Each CRTC may have one or more outputs associated with it.  This structure
+ * allows the CRTC to be controlled.
+ */
+struct drm_crtc {
+       struct drm_device *dev;
+       struct list_head head;
+
+       int id; /* idr assigned */
+
+       /* framebuffer the output is currently bound to */
+       struct drm_framebuffer *fb;
+
+       bool enabled;
+
+       /* JJJ: are these needed? */
+       bool cursor_in_range;
+       bool cursor_shown;
+
+       struct drm_display_mode mode;
+
+       int x, y;
+       struct drm_display_mode *desired_mode;
+       int desired_x, desired_y;
+       const struct drm_crtc_funcs *funcs;
+       void *driver_private;
+
+       /* RRCrtcPtr randr_crtc? */
+};
+
+extern struct drm_crtc *drm_crtc_create(struct drm_device *dev,
+                                       const struct drm_crtc_funcs *funcs);
+
+/**
+ * drm_output_funcs - control outputs on a given device
+ * @init: setup this output
+ * @dpms: set power state (see drm_crtc_funcs above)
+ * @save: save output state
+ * @restore: restore output state
+ * @mode_valid: is this mode valid on the given output?
+ * @mode_fixup: try to fixup proposed mode for this output
+ * @mode_set: set this mode
+ * @detect: is this output active?
+ * @get_modes: get mode list for this output
+ * @set_property: property for this output may need update
+ * @cleanup: output is going away, cleanup
+ *
+ * Each CRTC may have one or more outputs attached to it.  The functions
+ * below allow the core DRM code to control outputs, enumerate available modes,
+ * etc.
+ */
+struct drm_output_funcs {
+       void (*init)(struct drm_output *output);
+       void (*dpms)(struct drm_output *output, int mode);
+       void (*save)(struct drm_output *output);
+       void (*restore)(struct drm_output *output);
+       int (*mode_valid)(struct drm_output *output,
+                         struct drm_display_mode *mode);
+       bool (*mode_fixup)(struct drm_output *output,
+                          struct drm_display_mode *mode,
+                          struct drm_display_mode *adjusted_mode);
+       void (*prepare)(struct drm_output *output);
+       void (*commit)(struct drm_output *output);
+       void (*mode_set)(struct drm_output *output,
+                        struct drm_display_mode *mode,
+                        struct drm_display_mode *adjusted_mode);
+       enum drm_output_status (*detect)(struct drm_output *output);
+       int (*get_modes)(struct drm_output *output);
+       /* JJJ: type checking for properties via property value type */
+       bool (*set_property)(struct drm_output *output, struct drm_property *property,
+                            uint64_t val);
+       void (*cleanup)(struct drm_output *output);
+};
+
+#define DRM_OUTPUT_MAX_UMODES 16
+#define DRM_OUTPUT_MAX_PROPERTY 16
+#define DRM_OUTPUT_LEN 32
+/**
+ * drm_output - central DRM output control structure
+ * @crtc: CRTC this output is currently connected to, NULL if none
+ * @possible_crtcs: bitmap of CRTCS this output could be attached to
+ * @possible_clones: bitmap of possible outputs this output could clone
+ * @interlace_allowed: can this output handle interlaced modes?
+ * @doublescan_allowed: can this output handle doublescan?
+ * @available_modes: modes available on this output (from get_modes() + user)
+ * @initial_x: initial x position for this output
+ * @initial_y: initial y position for this output
+ * @status: output connected?
+ * @subpixel_order: for this output
+ * @mm_width: displayable width of output in mm
+ * @mm_height: displayable height of output in mm
+ * @funcs: output control functions
+ * @driver_private: private driver data
+ *
+ * Each output may be connected to one or more CRTCs, or may be clonable by
+ * another output if they can share a CRTC.  Each output also has a specific
+ * position in the broader display (referred to as a 'screen' though it could
+ * span multiple monitors).
+ */
+struct drm_output {
+       struct drm_device *dev;
+       struct list_head head;
+       struct drm_crtc *crtc;
+       int id; /* idr assigned */
+
+       int output_type;
+       int output_type_id;
+       unsigned long possible_crtcs;
+       unsigned long possible_clones;
+       bool interlace_allowed;
+       bool doublescan_allowed;
+       struct list_head modes; /* list of modes on this output */
+
+       /*
+         OptionInfoPtr options;
+         XF86ConfMonitorPtr conf_monitor;
+        */
+       int initial_x, initial_y;
+       enum drm_output_status status;
+
+       /* these are modes added by probing with DDC or the BIOS */
+       struct list_head probed_modes;
+       
+       /* xf86MonPtr MonInfo; */
+       enum subpixel_order subpixel_order;
+       int mm_width, mm_height;
+       struct drm_display_info *monitor_info; /* if any */
+       const struct drm_output_funcs *funcs;
+       void *driver_private;
+
+       struct list_head user_modes;
+       struct drm_property_blob *edid_blob_ptr;
+       u32 property_ids[DRM_OUTPUT_MAX_PROPERTY];
+       uint64_t property_values[DRM_OUTPUT_MAX_PROPERTY];
+};
+
+/**
+ * struct drm_mode_set
+ *
+ * Represents a single crtc the outputs that it drives with what mode
+ * and from which framebuffer it scans out from.
+ */
+struct drm_mode_set
+{
+       struct drm_framebuffer *fb;
+       struct drm_crtc *crtc;
+
+       struct drm_output **outputs;
+       size_t num_outputs;
+};
+
+/**
+ * struct drm_mode_config_funcs - configure CRTCs for a given screen layout
+ * @resize: adjust CRTCs as necessary for the proposed layout
+ *
+ * Currently only a resize hook is available.  DRM will call back into the
+ * driver with a new screen width and height.  If the driver can't support
+ * the proposed size, it can return false.  Otherwise it should adjust
+ * the CRTC<->output mappings as needed and update its view of the screen.
+ */
+struct drm_mode_config_funcs {
+       bool (*resize)(struct drm_device *dev, int width, int height);
+};
+
+/**
+ * drm_mode_config - Mode configuration control structure
+ *
+ */
+struct drm_mode_config {
+       struct mutex mutex; /* protects configuration and IDR */
+       struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, output, modes - just makes life easier */
+       /* this is limited to one for now */
+       int num_fb;
+       struct list_head fb_list;
+       int num_output;
+       struct list_head output_list;
+
+       /* int compat_output? */
+       int num_crtc;
+       struct list_head crtc_list;
+
+       struct list_head property_list;
+
+       int min_width, min_height;
+       int max_width, max_height;
+       /* DamagePtr rotationDamage? */
+       /* DGA stuff? */
+       struct drm_mode_config_funcs *funcs;
+       unsigned long fb_base;
+
+       /* pointers to standard properties */
+       struct list_head property_blob_list;
+       struct drm_property *edid_property;
+       struct drm_property *dpms_property;
+       struct drm_property *connector_type_property;
+       struct drm_property *connector_num_property;
+
+       /* TV properties */
+       struct drm_property *tv_mode_property;
+       struct drm_property *tv_left_margin_property;
+       struct drm_property *tv_right_margin_property;
+       struct drm_property *tv_top_margin_property;
+       struct drm_property *tv_bottom_margin_property;
+
+       /* hotplug */
+       uint32_t hotplug_counter;
+};
+
+struct drm_output *drm_output_create(struct drm_device *dev,
+                                    const struct drm_output_funcs *funcs,
+                                    int type);
+
+extern char *drm_get_output_name(struct drm_output *output);
+extern void drm_output_destroy(struct drm_output *output);
+extern void drm_fb_release(struct file *filp);
+
+extern struct edid *drm_get_edid(struct drm_output *output,
+                                struct i2c_adapter *adapter);
+extern int drm_add_edid_modes(struct drm_output *output, struct edid *edid);
+extern void drm_mode_probed_add(struct drm_output *output, struct drm_display_mode *mode);
+extern void drm_mode_remove(struct drm_output *output, struct drm_display_mode *mode);
+extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
+                                                  struct drm_display_mode *mode);
+extern void drm_mode_debug_printmodeline(struct drm_device *dev,
+                                        struct drm_display_mode *mode);
+extern void drm_mode_config_init(struct drm_device *dev);
+extern void drm_mode_config_cleanup(struct drm_device *dev);
+extern void drm_mode_set_name(struct drm_display_mode *mode);
+extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2);
+extern void drm_disable_unused_functions(struct drm_device *dev);
+
+/* for us by fb module */
+extern int drm_mode_attachmode_crtc(struct drm_device *dev,
+                                   struct drm_crtc *crtc,
+                                   struct drm_display_mode *mode);
+extern int drm_mode_detachmode_crtc(struct drm_device *dev, struct drm_display_mode *mode);
+
+extern struct drm_display_mode *drm_mode_create(struct drm_device *dev);
+extern void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode);
+extern void drm_mode_list_concat(struct list_head *head,
+                                struct list_head *new);
+extern void drm_mode_validate_size(struct drm_device *dev,
+                                  struct list_head *mode_list,
+                                  int maxX, int maxY, int maxPitch);
+extern void drm_mode_prune_invalid(struct drm_device *dev,
+                                  struct list_head *mode_list, bool verbose);
+extern void drm_mode_sort(struct list_head *mode_list);
+extern int drm_mode_vrefresh(struct drm_display_mode *mode);
+extern void drm_mode_set_crtcinfo(struct drm_display_mode *p,
+                                 int adjust_flags);
+extern void drm_mode_output_list_update(struct drm_output *output);
+extern int drm_mode_output_update_edid_property(struct drm_output *output,
+                                               struct edid *edid);
+extern int drm_output_property_set_value(struct drm_output *output,
+                                        struct drm_property *property,
+                                        uint64_t value);
+extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev);
+extern bool drm_initial_config(struct drm_device *dev, bool cangrow);
+extern void drm_framebuffer_set_object(struct drm_device *dev,
+                                      unsigned long handle);
+extern struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev);
+extern void drm_framebuffer_destroy(struct drm_framebuffer *fb);
+extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc);
+extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
+extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                      int x, int y);
+extern int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, bool connected);
+
+extern int drm_output_attach_property(struct drm_output *output,
+                                     struct drm_property *property, uint64_t init_val);
+extern struct drm_property *drm_property_create(struct drm_device *dev, int flags,
+                                               const char *name, int num_values);
+extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property);
+extern int drm_property_add_enum(struct drm_property *property, int index, 
+                                uint64_t value, const char *name);
+
+/* IOCTLs */
+extern int drm_mode_getresources(struct drm_device *dev,
+                                void *data, struct drm_file *file_priv);
+
+extern int drm_mode_getcrtc(struct drm_device *dev,
+                           void *data, struct drm_file *file_priv);
+extern int drm_mode_getoutput(struct drm_device *dev,
+                             void *data, struct drm_file *file_priv);
+extern int drm_mode_setcrtc(struct drm_device *dev,
+                           void *data, struct drm_file *file_priv);
+extern int drm_mode_cursor_ioctl(struct drm_device *dev,
+                               void *data, struct drm_file *file_priv);
+extern int drm_mode_addfb(struct drm_device *dev,
+                         void *data, struct drm_file *file_priv);
+extern int drm_mode_rmfb(struct drm_device *dev,
+                        void *data, struct drm_file *file_priv);
+extern int drm_mode_getfb(struct drm_device *dev,
+                         void *data, struct drm_file *file_priv);
+extern int drm_mode_addmode_ioctl(struct drm_device *dev,
+                                 void *data, struct drm_file *file_priv);
+extern int drm_mode_rmmode_ioctl(struct drm_device *dev,
+                                void *data, struct drm_file *file_priv);
+extern int drm_mode_attachmode_ioctl(struct drm_device *dev,
+                                    void *data, struct drm_file *file_priv);
+extern int drm_mode_detachmode_ioctl(struct drm_device *dev,
+                                    void *data, struct drm_file *file_priv);
+
+extern int drm_mode_getproperty_ioctl(struct drm_device *dev,
+                                     void *data, struct drm_file *file_priv);
+extern int drm_mode_getblob_ioctl(struct drm_device *dev,
+                                 void *data, struct drm_file *file_priv);
+extern int drm_mode_output_property_set_ioctl(struct drm_device *dev,
+                                             void *data, struct drm_file *file_priv);
+extern int drm_mode_hotplug_ioctl(struct drm_device *dev,
+                                 void *data, struct drm_file *file_priv);
+
+#endif /* __DRM_CRTC_H__ */
+
index b8b8333..434789d 100644 (file)
@@ -56,7 +56,7 @@ static int drm_version(struct drm_device *dev, void *data,
 
 /** Ioctl table */
 static struct drm_ioctl_desc drm_ioctls[] = {
-       DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, 0),
+       DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_CONTROL_ALLOW),
        DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0),
        DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0),
        DRM_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_irq_by_busid, DRM_MASTER|DRM_ROOT_ONLY),
@@ -121,6 +121,22 @@ static struct drm_ioctl_desc drm_ioctls[] = {
 
        DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETOUTPUT, drm_mode_getoutput, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
+
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_output_property_set_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_ROOT_ONLY | DRM_CONTROL_ALLOW),
+       DRM_IOCTL_DEF(DRM_IOCTL_MODE_HOTPLUG, drm_mode_hotplug_ioctl, DRM_CONTROL_ALLOW),
+
        DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl,
                      DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_IOCTL_MM_TAKEDOWN, drm_mm_takedown_ioctl,
@@ -166,31 +182,25 @@ static struct drm_ioctl_desc drm_ioctls[] = {
  */
 int drm_lastclose(struct drm_device * dev)
 {
-       struct drm_magic_entry *pt, *next;
-       struct drm_map_list *r_list, *list_t;
        struct drm_vma_entry *vma, *vma_temp;
        int i;
 
        DRM_DEBUG("\n");
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               drm_bo_driver_finish(dev);
+
        /*
         * We can't do much about this function failing.
         */
 
-       drm_bo_driver_finish(dev);
-
        if (dev->driver->lastclose)
                dev->driver->lastclose(dev);
        DRM_DEBUG("driver lastclose completed\n");
 
-       if (dev->unique) {
-               drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER);
-               dev->unique = NULL;
-               dev->unique_len = 0;
-       }
 
-       if (dev->irq_enabled)
-               drm_irq_uninstall(dev);
+/*     if (dev->irq_enabled)
+               drm_irq_uninstall(dev); */
 
        /* Free drawable information memory */
        mutex_lock(&dev->struct_mutex);
@@ -198,22 +208,11 @@ int drm_lastclose(struct drm_device * dev)
        drm_drawable_free_all(dev);
        del_timer(&dev->timer);
 
-       if (dev->unique) {
-               drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER);
-               dev->unique = NULL;
-               dev->unique_len = 0;
+       if (dev->primary->master) {
+               drm_put_master(dev->primary->master);
+               dev->primary->master = NULL;
        }
-
-       if (dev->magicfree.next) {
-               list_for_each_entry_safe(pt, next, &dev->magicfree, head) {
-                       list_del(&pt->head);
-                       drm_ht_remove_item(&dev->magiclist, &pt->hash_item);
-                       drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
-               }
-               drm_ht_remove(&dev->magiclist);
-       }
-
-
+       
        /* Clear AGP information */
        if (drm_core_has_AGP(dev) && dev->agp) {
                struct drm_agp_mem *entry, *tempe;
@@ -245,12 +244,13 @@ int drm_lastclose(struct drm_device * dev)
                drm_ctl_free(vma, sizeof(*vma), DRM_MEM_VMAS);
        }
 
+       /*
        list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) {
                if (!(r_list->map->flags & _DRM_DRIVER)) {
                        drm_rmmap_locked(dev, r_list->map);
                        r_list = NULL;
                }
-       }
+       }*/
 
        if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) {
                for (i = 0; i < dev->queue_count; i++) {
@@ -272,11 +272,6 @@ int drm_lastclose(struct drm_device * dev)
        if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))
                drm_dma_takedown(dev);
 
-       if (dev->lock.hw_lock) {
-               dev->sigdata.lock = dev->lock.hw_lock = NULL;   /* SHM removed */
-               dev->lock.file_priv = NULL;
-               wake_up_interruptible(&dev->lock.lock_queue);
-       }
        dev->dev_mapping = NULL;
        mutex_unlock(&dev->struct_mutex);
 
@@ -403,12 +398,14 @@ static void drm_cleanup(struct drm_device * dev)
                DRM_DEBUG("mtrr_del=%d\n", retval);
        }
 
+       if (dev->driver->unload)
+               dev->driver->unload(dev);
+        
+       drm_ht_remove(&dev->map_hash);
        if (drm_core_has_AGP(dev) && dev->agp) {
                drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
                dev->agp = NULL;
        }
-       if (dev->driver->unload)
-               dev->driver->unload(dev);
 
        if (!drm_fb_loaded)
                pci_disable_device(dev->pdev);
@@ -419,6 +416,8 @@ static void drm_cleanup(struct drm_device * dev)
        drm_ht_remove(&dev->object_hash);
 
        drm_put_minor(&dev->primary);
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               drm_put_minor(&dev->control);
        if (drm_put_dev(dev))
                DRM_ERROR("Cannot unload module\n");
 }
@@ -433,8 +432,14 @@ int drm_minors_cleanup(int id, void *ptr, void *data)
        if (minor->dev->driver != driver)
                return 0;
 
-       if (minor->type != DRM_MINOR_LEGACY)
-               return 0;
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               if (minor->type != DRM_MINOR_CONTROL)
+                       return 0;
+       } else {
+               if (minor->type != DRM_MINOR_LEGACY)
+                       return 0;
+       }
+
 
        if (dev)
                pci_dev_put(dev->pdev);
@@ -619,6 +624,7 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                retcode = -EINVAL;
                goto err_i1;
        }
+         
 #if 0
        /*
         * This check is disabled, because driver private ioctl->cmd
@@ -649,7 +655,8 @@ long drm_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                retcode = -EINVAL;
        } else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) ||
                   ((ioctl->flags & DRM_AUTH) && !file_priv->authenticated) ||
-                  ((ioctl->flags & DRM_MASTER) && !file_priv->master)) {
+                  ((ioctl->flags & DRM_MASTER) && !file_priv->master) ||
+                  ((!(ioctl->flags & DRM_CONTROL_ALLOW)) && (file_priv->minor->type == DRM_MINOR_CONTROL)) ) {
                retcode = -EACCES;
        } else {
                retcode = func(dev, kdata, file_priv);
diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c
new file mode 100644 (file)
index 0000000..9762567
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2007 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * DDC probing routines (drm_ddc_read & drm_do_probe_ddc_edid) originally from
+ * FB layer.
+ *   Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.com>
+ */
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include "drmP.h"
+#include "drm_edid.h"
+
+/* Valid EDID header has these bytes */
+static u8 edid_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
+
+/**
+ * edid_valid - sanity check EDID data
+ * @edid: EDID data
+ *
+ * Sanity check the EDID block by looking at the header, the version number
+ * and the checksum.  Return 0 if the EDID doesn't check out, or 1 if it's
+ * valid.
+ */
+static bool edid_valid(struct edid *edid)
+{
+       int i;
+       u8 csum = 0;
+       u8 *raw_edid = (u8 *)edid;
+
+       if (memcmp(edid->header, edid_header, sizeof(edid_header)))
+               goto bad;
+       if (edid->version != 1)
+               goto bad;
+       if (edid->revision <= 0 || edid->revision > 3)
+               goto bad;
+
+       for (i = 0; i < EDID_LENGTH; i++)
+               csum += raw_edid[i];
+       if (csum)
+               goto bad;
+
+       return 1;
+
+bad:
+       return 0;
+}
+
+/**
+ * drm_mode_std - convert standard mode info (width, height, refresh) into mode
+ * @t: standard timing params
+ *
+ * Take the standard timing params (in this case width, aspect, and refresh)
+ * and convert them into a real mode using CVT.
+ *
+ * Punts for now, but should eventually use the FB layer's CVT based mode
+ * generation code.
+ */
+struct drm_display_mode *drm_mode_std(struct drm_device *dev,
+                                     struct std_timing *t)
+{
+//     struct fb_videomode mode;
+
+//     fb_find_mode_cvt(&mode, 0, 0);
+       /* JJJ:  convert to drm_display_mode */
+       struct drm_display_mode *mode;
+       int hsize = t->hsize * 8 + 248, vsize;
+
+       mode = drm_mode_create(dev);
+       if (!mode)
+               return NULL;
+
+       if (t->aspect_ratio == 0)
+               vsize = (hsize * 10) / 16;
+       else if (t->aspect_ratio == 1)
+               vsize = (hsize * 3) / 4;
+       else if (t->aspect_ratio == 2)
+               vsize = (hsize * 4) / 5;
+       else
+               vsize = (hsize * 9) / 16;
+
+       drm_mode_set_name(mode);
+
+       return mode;
+}
+
+/**
+ * drm_mode_detailed - create a new mode from an EDID detailed timing section
+ * @timing: EDID detailed timing info
+ * @preferred: is this a preferred mode?
+ *
+ * An EDID detailed timing block contains enough info for us to create and
+ * return a new struct drm_display_mode.  The @preferred flag will be set
+ * if this is the display's preferred timing, and we'll use it to indicate
+ * to the other layers that this mode is desired.
+ */
+struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
+                                          struct detailed_timing *timing)
+{
+       struct drm_display_mode *mode;
+       struct detailed_pixel_timing *pt = &timing->data.pixel_data;
+
+       if (pt->stereo) {
+               printk(KERN_WARNING "stereo mode not supported\n");
+               return NULL;
+       }
+       if (!pt->separate_sync) {
+               printk(KERN_WARNING "integrated sync not supported\n");
+               return NULL;
+       }
+
+       mode = drm_mode_create(dev);
+       if (!mode)
+               return NULL;
+
+       mode->type = DRM_MODE_TYPE_DRIVER;
+       mode->clock = timing->pixel_clock * 10;
+
+       mode->hdisplay = (pt->hactive_hi << 8) | pt->hactive_lo;
+       mode->hsync_start = mode->hdisplay + ((pt->hsync_offset_hi << 8) |
+                                             pt->hsync_offset_lo);
+       mode->hsync_end = mode->hsync_start +
+               ((pt->hsync_pulse_width_hi << 8) |
+                pt->hsync_pulse_width_lo);
+       mode->htotal = mode->hdisplay + ((pt->hblank_hi << 8) | pt->hblank_lo);
+
+       mode->vdisplay = (pt->vactive_hi << 8) | pt->vactive_lo;
+       mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 8) |
+                                             pt->vsync_offset_lo);
+       mode->vsync_end = mode->vsync_start +
+               ((pt->vsync_pulse_width_hi << 8) |
+                pt->vsync_pulse_width_lo);
+       mode->vtotal = mode->vdisplay + ((pt->vblank_hi << 8) | pt->vblank_lo);
+
+       drm_mode_set_name(mode);
+
+       if (pt->interlaced)
+               mode->flags |= V_INTERLACE;
+
+       mode->flags |= pt->hsync_positive ? V_PHSYNC : V_NHSYNC;
+       mode->flags |= pt->vsync_positive ? V_PVSYNC : V_NVSYNC;
+
+       return mode;
+}
+
+/*
+ * Detailed mode info for the EDID "established modes" data to use.
+ */
+static struct drm_display_mode edid_est_modes[] = {
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
+                  968, 1056, 0, 600, 601, 605, 628, 0,
+                  V_PHSYNC | V_PVSYNC) }, /* 800x600@60Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824,
+                  896, 1024, 0, 600, 601, 603,  625, 0,
+                  V_PHSYNC | V_PVSYNC) }, /* 800x600@56Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656,
+                  720, 840, 0, 480, 481, 484, 500, 0,
+                  V_NHSYNC | V_NVSYNC) }, /* 640x480@75Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664,
+                  704,  832, 0, 480, 489, 491, 520, 0,
+                  V_NHSYNC | V_NVSYNC) }, /* 640x480@72Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704,
+                  768,  864, 0, 480, 483, 486, 525, 0,
+                  V_NHSYNC | V_NVSYNC) }, /* 640x480@67Hz */
+       { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656,
+                  752, 800, 0, 480, 490, 492, 525, 0,
+                  V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */
+       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738,
+                  846, 900, 0, 400, 421, 423,  449, 0,
+                  V_NHSYNC | V_NVSYNC) }, /* 720x400@88Hz */
+       { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738,
+                  846,  900, 0, 400, 412, 414, 449, 0,
+                  V_NHSYNC | V_PVSYNC) }, /* 720x400@70Hz */
+       { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296,
+                  1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
+                  V_PHSYNC | V_PVSYNC) }, /* 1280x1024@75Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040,
+                  1136, 1312, 0,  768, 769, 772, 800, 0,
+                  V_PHSYNC | V_PVSYNC) }, /* 1024x768@75Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048,
+                  1184, 1328, 0,  768, 771, 777, 806, 0,
+                  V_NHSYNC | V_NVSYNC) }, /* 1024x768@70Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
+                  1184, 1344, 0,  768, 771, 777, 806, 0,
+                  V_NHSYNC | V_NVSYNC) }, /* 1024x768@60Hz */
+       { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032,
+                  1208, 1264, 0, 768, 768, 776, 817, 0,
+                  V_PHSYNC | V_PVSYNC | V_INTERLACE) }, /* 1024x768@43Hz */
+       { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864,
+                  928, 1152, 0, 624, 625, 628, 667, 0,
+                  V_NHSYNC | V_NVSYNC) }, /* 832x624@75Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816,
+                  896, 1056, 0, 600, 601, 604,  625, 0,
+                  V_PHSYNC | V_PVSYNC) }, /* 800x600@75Hz */
+       { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856,
+                  976, 1040, 0, 600, 637, 643, 666, 0,
+                  V_PHSYNC | V_PVSYNC) }, /* 800x600@72Hz */
+       { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
+                  1344, 1600, 0,  864, 865, 868, 900, 0,
+                  V_PHSYNC | V_PVSYNC) }, /* 1152x864@75Hz */
+};
+
+#define EDID_EST_TIMINGS 16
+#define EDID_STD_TIMINGS 8
+#define EDID_DETAILED_TIMINGS 4
+
+/**
+ * add_established_modes - get est. modes from EDID and add them
+ * @edid: EDID block to scan
+ *
+ * Each EDID block contains a bitmap of the supported "established modes" list
+ * (defined above).  Tease them out and add them to the global modes list.
+ */
+static int add_established_modes(struct drm_output *output, struct edid *edid)
+{
+       struct drm_device *dev = output->dev;
+       unsigned long est_bits = edid->established_timings.t1 |
+               (edid->established_timings.t2 << 8) |
+               ((edid->established_timings.mfg_rsvd & 0x80) << 9);
+       int i, modes = 0;
+
+       for (i = 0; i <= EDID_EST_TIMINGS; i++)
+               if (est_bits & (1<<i)) {
+                       struct drm_display_mode *newmode;
+                       newmode = drm_mode_duplicate(dev, &edid_est_modes[i]);
+                       if (newmode) {
+                               drm_mode_probed_add(output, newmode);
+                               modes++;
+                       }
+               }
+
+       return modes;
+}
+
+/**
+ * add_standard_modes - get std. modes from EDID and add them
+ * @edid: EDID block to scan
+ *
+ * Standard modes can be calculated using the CVT standard.  Grab them from
+ * @edid, calculate them, and add them to the list.
+ */
+static int add_standard_modes(struct drm_output *output, struct edid *edid)
+{
+       struct drm_device *dev = output->dev;
+       int i, modes = 0;
+
+       for (i = 0; i < EDID_STD_TIMINGS; i++) {
+               struct std_timing *t = &edid->standard_timings[i];
+               struct drm_display_mode *newmode;
+
+               /* If std timings bytes are 1, 1 it's empty */
+               if (t->hsize == 1 && (t->aspect_ratio | t->vfreq) == 1)
+                       continue;
+
+               newmode = drm_mode_std(dev, &edid->standard_timings[i]);
+               if (newmode) {
+                       drm_mode_probed_add(output, newmode);
+                       modes++;
+               }
+       }
+
+       return modes;
+}
+
+/**
+ * add_detailed_modes - get detailed mode info from EDID data
+ * @edid: EDID block to scan
+ *
+ * Some of the detailed timing sections may contain mode information.  Grab
+ * it and add it to the list.
+ */
+static int add_detailed_info(struct drm_output *output, struct edid *edid)
+{
+       struct drm_device *dev = output->dev;
+       int i, j, modes = 0;
+
+       for (i = 0; i < EDID_DETAILED_TIMINGS; i++) {
+               struct detailed_timing *timing = &edid->detailed_timings[i];
+               struct detailed_non_pixel *data = &timing->data.other_data;
+               struct drm_display_mode *newmode;
+
+               /* EDID up to and including 1.2 may put monitor info here */
+               if (edid->version == 1 && edid->revision < 3)
+                       continue;
+
+               /* Detailed mode timing */
+               if (timing->pixel_clock) {
+                       newmode = drm_mode_detailed(dev, timing);
+                       /* First detailed mode is preferred */
+                       if (newmode) {
+                               if (i == 0 && edid->preferred_timing)
+                                       newmode->type |= DRM_MODE_TYPE_PREFERRED;
+                               drm_mode_probed_add(output, newmode);
+                                    
+                               modes++;
+                       }
+                       continue;
+               }
+
+               /* Other timing or info */
+               switch (data->type) {
+               case EDID_DETAIL_MONITOR_SERIAL:
+                       break;
+               case EDID_DETAIL_MONITOR_STRING:
+                       break;
+               case EDID_DETAIL_MONITOR_RANGE:
+                       /* Get monitor range data */
+                       break;
+               case EDID_DETAIL_MONITOR_NAME:
+                       break;
+               case EDID_DETAIL_MONITOR_CPDATA:
+                       break;
+               case EDID_DETAIL_STD_MODES:
+                       /* Five modes per detailed section */
+                       for (j = 0; j < 5; i++) {
+                               struct std_timing *std;
+                               struct drm_display_mode *newmode;
+
+                               std = &data->data.timings[j];
+                               newmode = drm_mode_std(dev, std);
+                               if (newmode) {
+                                       drm_mode_probed_add(output, newmode);
+                                       modes++;
+                               }
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return modes;
+}
+
+#define DDC_ADDR 0x50
+
+static unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter)
+{
+       unsigned char start = 0x0;
+       unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+       struct i2c_msg msgs[] = {
+               {
+                       .addr   = DDC_ADDR,
+                       .flags  = 0,
+                       .len    = 1,
+                       .buf    = &start,
+               }, {
+                       .addr   = DDC_ADDR,
+                       .flags  = I2C_M_RD,
+                       .len    = EDID_LENGTH,
+                       .buf    = buf,
+               }
+       };
+
+       if (!buf) {
+               dev_warn(&adapter->dev, "unable to allocate memory for EDID "
+                        "block.\n");
+               return NULL;
+       }
+
+       if (i2c_transfer(adapter, msgs, 2) == 2)
+               return buf;
+
+       dev_info(&adapter->dev, "unable to read EDID block.\n");
+       kfree(buf);
+       return NULL;
+}
+
+static unsigned char *drm_ddc_read(struct i2c_adapter *adapter)
+{
+       struct i2c_algo_bit_data *algo_data = adapter->algo_data;
+       unsigned char *edid = NULL;
+       int i, j;
+
+       /*
+        * Startup the bus:
+        *   Set clock line high (but give it time to come up)
+        *   Then set clock & data low
+        */
+       algo_data->setscl(algo_data->data, 1);
+       udelay(550); /* startup delay */
+       algo_data->setscl(algo_data->data, 0);
+       algo_data->setsda(algo_data->data, 0);
+
+       for (i = 0; i < 3; i++) {
+               /* For some old monitors we need the
+                * following process to initialize/stop DDC
+                */
+               algo_data->setsda(algo_data->data, 0);
+               msleep(13);
+
+               algo_data->setscl(algo_data->data, 1);
+               for (j = 0; j < 5; j++) {
+                       msleep(10);
+                       if (algo_data->getscl(algo_data->data))
+                               break;
+               }
+               if (j == 5)
+                       continue;
+
+               algo_data->setsda(algo_data->data, 0);
+               msleep(15);
+               algo_data->setscl(algo_data->data, 0);
+               msleep(15);
+               algo_data->setsda(algo_data->data, 1);
+               msleep(15);
+
+               /* Do the real work */
+               edid = drm_do_probe_ddc_edid(adapter);
+               algo_data->setsda(algo_data->data, 0);
+               algo_data->setscl(algo_data->data, 0);
+               msleep(15);
+
+               algo_data->setscl(algo_data->data, 1);
+               for (j = 0; j < 10; j++) {
+                       msleep(10);
+                       if (algo_data->getscl(algo_data->data))
+                               break;
+               }
+
+               algo_data->setsda(algo_data->data, 1);
+               msleep(15);
+               algo_data->setscl(algo_data->data, 0);
+               if (edid)
+                       break;
+       }
+       /* Release the DDC lines when done or the Apple Cinema HD display
+        * will switch off
+        */
+       algo_data->setsda(algo_data->data, 0);
+       algo_data->setscl(algo_data->data, 0);
+       algo_data->setscl(algo_data->data, 1);
+
+       return edid;
+}
+
+/**
+ * drm_get_edid - get EDID data, if available
+ * @output: output we're probing
+ * @adapter: i2c adapter to use for DDC
+ *
+ * Poke the given output's i2c channel to grab EDID data if possible.
+ * 
+ * Return edid data or NULL if we couldn't find any.
+ */
+struct edid *drm_get_edid(struct drm_output *output,
+                         struct i2c_adapter *adapter)
+{
+       struct edid *edid;
+
+       edid = (struct edid *)drm_ddc_read(adapter);
+       if (!edid) {
+               dev_warn(&output->dev->pdev->dev, "%s: no EDID data\n",
+                        drm_get_output_name(output));
+               return NULL;
+       }
+       if (!edid_valid(edid)) {
+               dev_warn(&output->dev->pdev->dev, "%s: EDID invalid.\n",
+                        drm_get_output_name(output));
+               kfree(edid);
+               return NULL;
+       }
+       return edid;
+}
+EXPORT_SYMBOL(drm_get_edid);
+
+/**
+ * drm_add_edid_modes - add modes from EDID data, if available
+ * @output: output we're probing
+ * @edid: edid data
+ *
+ * Add the specified modes to the output's mode list.
+ *
+ * Return number of modes added or 0 if we couldn't find any.
+ */
+int drm_add_edid_modes(struct drm_output *output, struct edid *edid)
+{
+       int num_modes = 0;
+
+       if (edid == NULL) {
+               return 0;
+       }
+       if (!edid_valid(edid)) {
+               dev_warn(&output->dev->pdev->dev, "%s: EDID invalid.\n",
+                        drm_get_output_name(output));
+               return 0;
+       }
+       num_modes += add_established_modes(output, edid);
+       num_modes += add_standard_modes(output, edid);
+       num_modes += add_detailed_info(output, edid);
+       return num_modes;
+}
+EXPORT_SYMBOL(drm_add_edid_modes);
diff --git a/linux-core/drm_edid.h b/linux-core/drm_edid.h
new file mode 100644 (file)
index 0000000..0d2eeaa
--- /dev/null
@@ -0,0 +1,176 @@
+#ifndef __DRM_EDID_H__
+#define __DRM_EDID_H__
+
+#include <linux/types.h>
+
+#define EDID_LENGTH 128
+#define DDC_ADDR 0x50
+
+#ifdef BIG_ENDIAN
+#error "EDID structure is little endian, need big endian versions"
+#endif
+
+struct est_timings {
+       u8 t1;
+       u8 t2;
+       u8 mfg_rsvd;
+} __attribute__((packed));
+
+struct std_timing {
+       u8 hsize; /* need to multiply by 8 then add 248 */
+       u8 vfreq:6; /* need to add 60 */
+       u8 aspect_ratio:2; /* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */
+} __attribute__((packed));
+
+/* If detailed data is pixel timing */
+struct detailed_pixel_timing {
+       u8 hactive_lo;
+       u8 hblank_lo;
+       u8 hblank_hi:4;
+       u8 hactive_hi:4;
+       u8 vactive_lo;
+       u8 vblank_lo;
+       u8 vblank_hi:4;
+       u8 vactive_hi:4;
+       u8 hsync_offset_lo;
+       u8 hsync_pulse_width_lo;
+       u8 vsync_pulse_width_lo:4;
+       u8 vsync_offset_lo:4;
+       u8 hsync_pulse_width_hi:2;
+       u8 hsync_offset_hi:2;
+       u8 vsync_pulse_width_hi:2;
+       u8 vsync_offset_hi:2;
+       u8 width_mm_lo;
+       u8 height_mm_lo;
+       u8 height_mm_hi:4;
+       u8 width_mm_hi:4;
+       u8 hborder;
+       u8 vborder;
+       u8 unknown0:1;
+       u8 vsync_positive:1;
+       u8 hsync_positive:1;
+       u8 separate_sync:2;
+       u8 stereo:1;
+       u8 unknown6:1;
+       u8 interlaced:1;
+} __attribute__((packed));
+
+/* If it's not pixel timing, it'll be one of the below */
+struct detailed_data_string {
+       u8 str[13];
+} __attribute__((packed));
+
+struct detailed_data_monitor_range {
+       u8 min_vfreq;
+       u8 max_vfreq;
+       u8 min_hfreq_khz;
+       u8 max_hfreq_khz;
+       u8 pixel_clock_mhz; /* need to multiply by 10 */
+       u16 sec_gtf_toggle; /* A000=use above, 20=use below */ /* FIXME: byte order */
+       u8 hfreq_start_khz; /* need to multiply by 2 */
+       u8 c; /* need to divide by 2 */
+       u16 m; /* FIXME: byte order */
+       u8 k;
+       u8 j; /* need to divide by 2 */
+} __attribute__((packed));
+
+struct detailed_data_wpindex {
+       u8 white_y_lo:2;
+       u8 white_x_lo:2;
+       u8 pad:4;
+       u8 white_x_hi;
+       u8 white_y_hi;
+       u8 gamma; /* need to divide by 100 then add 1 */
+} __attribute__((packed));
+
+struct detailed_data_color_point {
+       u8 windex1;
+       u8 wpindex1[3];
+       u8 windex2;
+       u8 wpindex2[3];
+} __attribute__((packed));
+
+struct detailed_non_pixel {
+       u8 pad1;
+       u8 type; /* ff=serial, fe=string, fd=monitor range, fc=monitor name
+                   fb=color point data, fa=standard timing data,
+                   f9=undefined, f8=mfg. reserved */
+       u8 pad2;
+       union {
+               struct detailed_data_string str;
+               struct detailed_data_monitor_range range;
+               struct detailed_data_wpindex color;
+               struct std_timing timings[5];
+       } data;
+} __attribute__((packed));
+
+#define EDID_DETAIL_STD_MODES 0xfa
+#define EDID_DETAIL_MONITOR_CPDATA 0xfb
+#define EDID_DETAIL_MONITOR_NAME 0xfc
+#define EDID_DETAIL_MONITOR_RANGE 0xfd
+#define EDID_DETAIL_MONITOR_STRING 0xfe
+#define EDID_DETAIL_MONITOR_SERIAL 0xff
+
+struct detailed_timing {
+       u16 pixel_clock; /* need to multiply by 10 KHz */ /* FIXME: byte order */
+       union {
+               struct detailed_pixel_timing pixel_data;
+               struct detailed_non_pixel other_data;
+       } data;
+} __attribute__((packed));
+
+struct edid {
+       u8 header[8];
+       /* Vendor & product info */
+       u16 mfg_id; /* FIXME: byte order */
+       u16 prod_code; /* FIXME: byte order */
+       u32 serial; /* FIXME: byte order */
+       u8 mfg_week;
+       u8 mfg_year;
+       /* EDID version */
+       u8 version;
+       u8 revision;
+       /* Display info: */
+       /*   input definition */
+       u8 serration_vsync:1;
+       u8 sync_on_green:1;
+       u8 composite_sync:1;
+       u8 separate_syncs:1;
+       u8 blank_to_black:1;
+       u8 video_level:2;
+       u8 digital:1; /* bits below must be zero if set */
+       u8 width_cm;
+       u8 height_cm;
+       u8 gamma;
+       /*   feature support */
+       u8 default_gtf:1;
+       u8 preferred_timing:1;
+       u8 standard_color:1;
+       u8 display_type:2; /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */
+       u8 pm_active_off:1;
+       u8 pm_suspend:1;
+       u8 pm_standby:1;
+       /* Color characteristics */
+       u8 red_green_lo;
+       u8 black_white_lo;
+       u8 red_x;
+       u8 red_y;
+       u8 green_x;
+       u8 green_y;
+       u8 blue_x;
+       u8 blue_y;
+       u8 white_x;
+       u8 white_y;
+       /* Est. timings and mfg rsvd timings*/
+       struct est_timings established_timings;
+       /* Standard timings 1-8*/
+       struct std_timing standard_timings[8];
+       /* Detailing timings 1-4 */
+       struct detailed_timing detailed_timings[4];
+       /* Number of 128 byte ext. blocks */
+       u8 extensions;
+       /* Checksum */
+       u8 checksum;
+} __attribute__((packed));
+
+#endif /* __DRM_EDID_H__ */
diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c
new file mode 100644 (file)
index 0000000..775fd18
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * Copyright Â© 2007 David Airlie
+ *
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ *     David Airlie
+ */
+    /*
+     *  Modularization
+     */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
+#include "drmP.h"
+#include "drm_crtc.h"
+
+struct drmfb_par {
+       struct drm_device *dev;
+       struct drm_crtc *crtc;
+};
+
+static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                          unsigned blue, unsigned transp,
+                          struct fb_info *info)
+{
+       struct drmfb_par *par = info->par;
+       struct drm_framebuffer *fb = par->crtc->fb;
+       struct drm_crtc *crtc = par->crtc;
+
+       if (regno > 255)
+               return 1;
+
+       if (fb->depth == 8) {
+               if (crtc->funcs->gamma_set) {
+                       crtc->funcs->gamma_set(crtc, red, green, blue, regno);
+               }
+               return 0;
+       }
+       
+       if (regno < 16) {
+               switch (fb->depth) {
+               case 15:
+                       fb->pseudo_palette[regno] = ((red & 0xf800) >>  1) |
+                               ((green & 0xf800) >>  6) |
+                               ((blue & 0xf800) >> 11);
+                       break;
+               case 16:
+                       fb->pseudo_palette[regno] = (red & 0xf800) |
+                               ((green & 0xfc00) >>  5) |
+                               ((blue  & 0xf800) >> 11);
+                       break;
+               case 24:
+               case 32:
+                       fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
+                               (green & 0xff00) |
+                               ((blue  & 0xff00) >> 8);
+                       break;
+               }
+        }
+
+       return 0;
+}
+
+static int drmfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct drmfb_par *par = info->par;
+       struct drm_device *dev = par->dev;
+       struct drm_framebuffer *fb = par->crtc->fb;
+       struct drm_display_mode *drm_mode;
+       struct drm_output *output;
+       int depth;
+
+       if (!var->pixclock)
+               return -EINVAL;
+
+       /* Need to resize the fb object !!! */
+       if (var->xres > fb->width || var->yres > fb->height) {
+               DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height);
+               DRM_ERROR("Need resizing code.\n");
+               return -EINVAL;
+       }
+
+       switch (var->bits_per_pixel) {
+       case 16:
+               depth = (var->green.length == 6) ? 16 : 15;
+               break;
+       case 32:
+               depth = (var->transp.length > 0) ? 32 : 24;
+               break;
+       default:
+               depth = var->bits_per_pixel;
+               break;
+       }
+               
+       switch (depth) {
+       case 8:
+               var->red.offset = 0;
+               var->green.offset = 0;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 15:
+               var->red.offset = 10;
+               var->green.offset = 5;
+               var->blue.offset = 0;
+               var->red.length = 5;
+               var->green.length = 5;
+               var->blue.length = 5;
+               var->transp.length = 1;
+               var->transp.offset = 15;
+               break;
+       case 16:
+               var->red.offset = 11;
+               var->green.offset = 6;
+               var->blue.offset = 0;
+               var->red.length = 5;
+               var->green.length = 6;
+               var->blue.length = 5;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 24:
+               var->red.offset = 16;
+               var->green.offset = 8;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 32:
+               var->red.offset = 16;
+               var->green.offset = 8;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 8;
+               var->transp.offset = 24;
+               break;
+       default:
+               return -EINVAL; 
+       }
+
+#if 0
+       /* Here we walk the output mode list and look for modes. If we haven't
+        * got it, then bail. Not very nice, so this is disabled.
+        * In the set_par code, we create our mode based on the incoming
+        * parameters. Nicer, but may not be desired by some.
+        */
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+               if (output->crtc == par->crtc)
+                       break;
+       }
+    
+       list_for_each_entry(drm_mode, &output->modes, head) {
+               if (drm_mode->hdisplay == var->xres &&
+                   drm_mode->vdisplay == var->yres &&
+                   drm_mode->clock != 0)
+                   break;
+       }
+
+       if (!drm_mode)
+               return -EINVAL;
+#endif
+
+       return 0;
+}
+
+/* this will let fbcon do the mode init */
+static int drmfb_set_par(struct fb_info *info)
+{
+       struct drmfb_par *par = info->par;
+       struct drm_framebuffer *fb = par->crtc->fb;
+       struct drm_device *dev = par->dev;
+       struct drm_display_mode *drm_mode;
+       struct fb_var_screeninfo *var = &info->var;
+       struct drm_output *output;
+
+       switch (var->bits_per_pixel) {
+       case 16:
+               fb->depth = (var->green.length == 6) ? 16 : 15;
+               break;
+       case 32:
+               fb->depth = (var->transp.length > 0) ? 32 : 24;
+               break;
+       default:
+               fb->depth = var->bits_per_pixel;
+               break;
+       }
+
+       fb->bits_per_pixel = var->bits_per_pixel;
+
+       info->fix.line_length = fb->pitch;
+       info->fix.smem_len = info->fix.line_length * fb->height;
+       info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+
+       info->screen_size = info->fix.smem_len; /* ??? */
+
+       /* Should we walk the output's modelist or just create our own ???
+        * For now, we create and destroy a mode based on the incoming 
+        * parameters. But there's commented out code below which scans 
+        * the output list too.
+        */
+#if 0
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+               if (output->crtc == par->crtc)
+                       break;
+       }
+    
+       list_for_each_entry(drm_mode, &output->modes, head) {
+               if (drm_mode->hdisplay == var->xres &&
+                   drm_mode->vdisplay == var->yres &&
+                   drm_mode->clock != 0)
+                   break;
+       }
+#else
+       drm_mode = drm_mode_create(dev);
+       drm_mode->hdisplay = var->xres;
+       drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin;
+       drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len;
+       drm_mode->htotal = drm_mode->hsync_end + var->left_margin;
+       drm_mode->vdisplay = var->yres;
+       drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin;
+       drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len;
+       drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin;
+       drm_mode->clock = PICOS2KHZ(var->pixclock);
+       drm_mode->vrefresh = drm_mode_vrefresh(drm_mode);
+       drm_mode_set_name(drm_mode);
+       drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V);
+#endif
+
+       if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0))
+               return -EINVAL;
+
+       /* Have to destroy our created mode if we're not searching the mode
+        * list for it.
+        */
+#if 1 
+       drm_mode_destroy(dev, drm_mode);
+#endif
+
+       return 0;
+}
+
+static struct fb_ops drmfb_ops = {
+       .owner = THIS_MODULE,
+       //      .fb_open = drmfb_open,
+       //      .fb_read = drmfb_read,
+       //      .fb_write = drmfb_write,
+       //      .fb_release = drmfb_release,
+       //      .fb_ioctl = drmfb_ioctl,
+       .fb_check_var = drmfb_check_var,
+       .fb_set_par = drmfb_set_par,
+       .fb_setcolreg = drmfb_setcolreg,
+       .fb_fillrect = cfb_fillrect,
+       .fb_copyarea = cfb_copyarea,
+       .fb_imageblit = cfb_imageblit,
+};
+
+int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc)
+{
+       struct fb_info *info;
+       struct drm_framebuffer *fb = crtc->fb;
+       struct drmfb_par *par;
+       struct device *device = &dev->pdev->dev; 
+       struct drm_display_mode *mode = crtc->desired_mode;
+       int ret;
+
+       info = framebuffer_alloc(sizeof(struct drmfb_par), device);
+       if (!info)
+               return -ENOMEM;
+
+       fb->fbdev = info;
+               
+       par = info->par;
+
+       par->dev = dev;
+       par->crtc = crtc;
+
+       info->fbops = &drmfb_ops;
+
+       strcpy(info->fix.id, "drmfb");
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+       info->fix.visual = FB_VISUAL_TRUECOLOR;
+       info->fix.accel = FB_ACCEL_NONE;
+       info->fix.type_aux = 0;
+       info->fix.mmio_start = 0;
+       info->fix.mmio_len = 0;
+       info->fix.line_length = fb->pitch;
+       info->fix.smem_start = fb->offset + dev->mode_config.fb_base;
+       info->fix.smem_len = info->fix.line_length * fb->height;
+
+       info->flags = FBINFO_DEFAULT;
+
+       ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base);
+       if (ret)
+               DRM_ERROR("error mapping fb: %d\n", ret);
+
+       info->screen_base = fb->virtual_base;
+       info->screen_size = info->fix.smem_len; /* ??? */
+       info->pseudo_palette = fb->pseudo_palette;
+       info->var.xres_virtual = fb->width;
+       info->var.yres_virtual = fb->height;
+       info->var.bits_per_pixel = fb->bits_per_pixel;
+       info->var.xoffset = 0;
+       info->var.yoffset = 0;
+       info->var.activate = FB_ACTIVATE_NOW;
+       info->var.height = -1;
+       info->var.width = -1;
+       info->var.vmode = FB_VMODE_NONINTERLACED;
+
+       info->var.xres = mode->hdisplay;
+       info->var.right_margin = mode->hsync_start - mode->hdisplay;
+       info->var.hsync_len = mode->hsync_end - mode->hsync_start;
+       info->var.left_margin = mode->htotal - mode->hsync_end;
+       info->var.yres = mode->vdisplay;
+       info->var.lower_margin = mode->vsync_start - mode->vdisplay;
+       info->var.vsync_len = mode->vsync_end - mode->vsync_start;
+       info->var.upper_margin = mode->vtotal - mode->vsync_end;
+       info->var.pixclock = 10000000 / mode->htotal * 1000 /
+                               mode->vtotal * 100;
+       /* avoid overflow */
+       info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
+
+       DRM_DEBUG("fb depth is %d\n", fb->depth);
+       switch(fb->depth) {
+       case 8:
+               info->var.red.offset = 0;
+               info->var.green.offset = 0;
+               info->var.blue.offset = 0;
+               info->var.red.length = 8; /* 8bit DAC */
+               info->var.green.length = 8;
+               info->var.blue.length = 8;
+               info->var.transp.offset = 0;
+               info->var.transp.length = 0;
+               break;
+       case 15:
+               info->var.red.offset = 10;
+               info->var.green.offset = 5;
+               info->var.blue.offset = 0;
+               info->var.red.length = info->var.green.length =
+                       info->var.blue.length = 5;
+               info->var.transp.offset = 15;
+               info->var.transp.length = 1;
+               break;
+       case 16:
+               info->var.red.offset = 11;
+               info->var.green.offset = 5;
+               info->var.blue.offset = 0;
+               info->var.red.length = 5;
+               info->var.green.length = 6;
+               info->var.blue.length = 5;
+               info->var.transp.offset = 0;
+               info->var.transp.length = 0;
+               break;
+       case 24:
+               info->var.red.offset = 16;
+               info->var.green.offset = 8;
+               info->var.blue.offset = 0;
+               info->var.red.length = info->var.green.length =
+                       info->var.blue.length = 8;
+               info->var.transp.offset = 0;
+               info->var.transp.length = 0;
+               break;
+       case 32:
+               info->var.red.offset = 16;
+               info->var.green.offset = 8;
+               info->var.blue.offset = 0;
+               info->var.red.length = info->var.green.length =
+                       info->var.blue.length = 8;
+               info->var.transp.offset = 24;
+               info->var.transp.length = 8;
+               break;
+       default:
+               break;
+       }
+
+       if (register_framebuffer(info) < 0) {
+               unregister_framebuffer(info);
+               return -EINVAL;
+       }
+
+       printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+              info->fix.id);
+       return 0;
+}
+EXPORT_SYMBOL(drmfb_probe);
+
+int drmfb_remove(struct drm_device *dev, struct drm_crtc *crtc)
+{
+       struct fb_info *info = fb->fbdev;
+       struct drm_framebuffer *fb = crtc->fb;
+       
+       if (info) {
+               drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base);
+               unregister_framebuffer(info);
+               framebuffer_release(info);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(drmfb_remove);
+MODULE_LICENSE("GPL");
index 7fe274a..fcadc54 100644 (file)
@@ -43,10 +43,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
 
 static int drm_setup(struct drm_device * dev)
 {
-       drm_local_map_t *map;
        int i;
        int ret;
-       int sareapage;
 
        if (dev->driver->firstopen) {
                ret = dev->driver->firstopen(dev);
@@ -54,14 +52,6 @@ static int drm_setup(struct drm_device * dev)
                        return ret;
        }
 
-       dev->magicfree.next = NULL;
-
-       /* prebuild the SAREA */
-       sareapage = max(SAREA_MAX, PAGE_SIZE);
-       i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
-       if (i != 0)
-               return i;
-
        atomic_set(&dev->ioctl_count, 0);
        atomic_set(&dev->vma_count, 0);
        dev->buf_use = 0;
@@ -76,11 +66,8 @@ static int drm_setup(struct drm_device * dev)
        for (i = 0; i < ARRAY_SIZE(dev->counts); i++)
                atomic_set(&dev->counts[i], 0);
 
-       drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER);
-       INIT_LIST_HEAD(&dev->magicfree);
-
        dev->sigdata.lock = NULL;
-       init_waitqueue_head(&dev->lock.lock_queue);
+
        dev->queue_count = 0;
        dev->queue_reserved = 0;
        dev->queue_slots = 0;
@@ -260,6 +247,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
 
        INIT_LIST_HEAD(&priv->lhead);
        INIT_LIST_HEAD(&priv->refd_objects);
+       INIT_LIST_HEAD(&priv->fbs);
 
        for (i = 0; i < _DRM_NO_REF_TYPES; ++i) {
                ret = drm_ht_create(&priv->refd_object_hash[i],
@@ -280,10 +268,35 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
                        goto out_free;
        }
 
+
+       /* if there is no current master make this fd it */
        mutex_lock(&dev->struct_mutex);
-       if (list_empty(&dev->filelist))
-               priv->master = 1;
+       if (!priv->minor->master) {
+               priv->minor->master = drm_get_master(priv->minor);
+               if (!priv->minor->master) {
+                       ret = -ENOMEM;
+                       goto out_free;
+               }
+
+               priv->is_master = 1;
+               priv->master = priv->minor->master;
+
+               mutex_unlock(&dev->struct_mutex);
+               if (dev->driver->master_create) {
+                       ret = dev->driver->master_create(dev, priv->master);
+                       if (ret) {
+                               drm_put_master(priv->minor->master);
+                               priv->minor->master = priv->master = NULL;
+                               mutex_unlock(&dev->struct_mutex);
+                               goto out_free;
+                       }
+               }
+       } else {
+               priv->master = priv->minor->master;
+               mutex_unlock(&dev->struct_mutex);
+       }
 
+       mutex_lock(&dev->struct_mutex);
        list_add(&priv->lhead, &dev->filelist);
        mutex_unlock(&dev->struct_mutex);
 
@@ -389,23 +402,23 @@ int drm_release(struct inode *inode, struct file *filp)
                  current->pid, (long)old_encode_dev(file_priv->minor->device),
                  dev->open_count);
 
-       if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) {
+       if (dev->driver->reclaim_buffers_locked && file_priv->master->lock.hw_lock) {
                if (drm_i_have_hw_lock(dev, file_priv)) {
                        dev->driver->reclaim_buffers_locked(dev, file_priv);
                } else {
                        unsigned long _end=jiffies + 3*DRM_HZ;
                        int locked = 0;
 
-                       drm_idlelock_take(&dev->lock);
+                       drm_idlelock_take(&file_priv->master->lock);
 
                        /*
                         * Wait for a while.
                         */
 
                        do{
-                               spin_lock(&dev->lock.spinlock);
-                               locked = dev->lock.idle_has_lock;
-                               spin_unlock(&dev->lock.spinlock);
+                               spin_lock(&file_priv->master->lock.spinlock);
+                               locked = file_priv->master->lock.idle_has_lock;
+                               spin_unlock(&file_priv->master->lock.spinlock);
                                if (locked)
                                        break;
                                schedule();
@@ -418,24 +431,24 @@ int drm_release(struct inode *inode, struct file *filp)
                        }
 
                        dev->driver->reclaim_buffers_locked(dev, file_priv);
-                       drm_idlelock_release(&dev->lock);
+                       drm_idlelock_release(&file_priv->master->lock);
                }
        }
 
-       if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) {
+       if (dev->driver->reclaim_buffers_idlelocked && file_priv->master->lock.hw_lock) {
 
-               drm_idlelock_take(&dev->lock);
+               drm_idlelock_take(&file_priv->master->lock);
                dev->driver->reclaim_buffers_idlelocked(dev, file_priv);
-               drm_idlelock_release(&dev->lock);
+               drm_idlelock_release(&file_priv->master->lock);
 
        }
 
        if (drm_i_have_hw_lock(dev, file_priv)) {
                DRM_DEBUG("File %p released, freeing lock for context %d\n",
-                         filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+                         filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
 
-               drm_lock_free(&dev->lock,
-                             _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+               drm_lock_free(&file_priv->master->lock,
+                             _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock));
        }
 
 
@@ -468,6 +481,16 @@ int drm_release(struct inode *inode, struct file *filp)
        }
        mutex_unlock(&dev->ctxlist_mutex);
 
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               drm_fb_release(filp);
+
+       file_priv->master = NULL;
+
+       if (file_priv->is_master) {
+              drm_put_master(file_priv->minor->master);
+              file_priv->minor->master = NULL;
+       }
+
        mutex_lock(&dev->struct_mutex);
        drm_object_release(filp);
        if (file_priv->remove_auth_on_close == 1) {
@@ -477,6 +500,8 @@ int drm_release(struct inode *inode, struct file *filp)
                        temp->authenticated = 0;
        }
        list_del(&file_priv->lhead);
+
+
        mutex_unlock(&dev->struct_mutex);
 
        if (dev->driver->postclose)
@@ -490,9 +515,9 @@ int drm_release(struct inode *inode, struct file *filp)
        atomic_inc(&dev->counts[_DRM_STAT_CLOSES]);
        spin_lock(&dev->count_lock);
        if (!--dev->open_count) {
-               if (atomic_read(&dev->ioctl_count) || dev->blocked) {
-                       DRM_ERROR("Device busy: %d %d\n",
-                                 atomic_read(&dev->ioctl_count), dev->blocked);
+               if (atomic_read(&dev->ioctl_count)) {
+                       DRM_ERROR("Device busy: %d\n",
+                                 atomic_read(&dev->ioctl_count));
                        spin_unlock(&dev->count_lock);
                        unlock_kernel();
                        return -EBUSY;
index 3df163d..e35126a 100644 (file)
@@ -53,12 +53,13 @@ int drm_getunique(struct drm_device *dev, void *data,
                  struct drm_file *file_priv)
 {
        struct drm_unique *u = data;
+       struct drm_master *master = file_priv->master;
 
-       if (u->unique_len >= dev->unique_len) {
-               if (copy_to_user(u->unique, dev->unique, dev->unique_len))
+       if (u->unique_len >= master->unique_len) {
+               if (copy_to_user(u->unique, master->unique, master->unique_len))
                        return -EFAULT;
        }
-       u->unique_len = dev->unique_len;
+       u->unique_len = master->unique_len;
 
        return 0;
 }
@@ -81,36 +82,37 @@ int drm_setunique(struct drm_device *dev, void *data,
                  struct drm_file *file_priv)
 {
        struct drm_unique *u = data;
+       struct drm_master *master = file_priv->master;
        int domain, bus, slot, func, ret;
 
-       if (dev->unique_len || dev->unique)
+       if (master->unique_len || master->unique)
                return -EBUSY;
 
        if (!u->unique_len || u->unique_len > 1024)
                return -EINVAL;
 
-       dev->unique_len = u->unique_len;
-       dev->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER);
-       if (!dev->unique)
+       master->unique_len = u->unique_len;
+       master->unique = drm_alloc(u->unique_len + 1, DRM_MEM_DRIVER);
+       if (!master->unique)
                return -ENOMEM;
-       if (copy_from_user(dev->unique, u->unique, dev->unique_len))
+       if (copy_from_user(master->unique, u->unique, master->unique_len))
                return -EFAULT;
 
-       dev->unique[dev->unique_len] = '\0';
+       master->unique[master->unique_len] = '\0';
 
        dev->devname =
            drm_alloc(strlen(dev->driver->pci_driver.name) +
-                     strlen(dev->unique) + 2, DRM_MEM_DRIVER);
+                     strlen(master->unique) + 2, DRM_MEM_DRIVER);
        if (!dev->devname)
                return -ENOMEM;
 
        sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
-               dev->unique);
+               master->unique);
 
        /* Return error if the busid submitted doesn't match the device's actual
         * busid.
         */
-       ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
+       ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func);
        if (ret != 3)
                return -EINVAL;
        domain = bus >> 8;
@@ -125,33 +127,35 @@ int drm_setunique(struct drm_device *dev, void *data,
        return 0;
 }
 
-static int drm_set_busid(struct drm_device * dev)
+static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
 {
+       struct drm_master *master = file_priv->master;
        int len;
-       if (dev->unique != NULL)
+
+       if (master->unique != NULL)
                return -EBUSY;
 
-       dev->unique_len = 40;
-       dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER);
-       if (dev->unique == NULL)
+       master->unique_len = 40;
+       master->unique = drm_alloc(master->unique_len + 1, DRM_MEM_DRIVER);
+       if (master->unique == NULL)
                return -ENOMEM;
 
-       len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d",
+       len = snprintf(master->unique, master->unique_len, "pci:%04x:%02x:%02x.%d",
                       drm_get_pci_domain(dev),
                       dev->pdev->bus->number,
                       PCI_SLOT(dev->pdev->devfn),
                       PCI_FUNC(dev->pdev->devfn));
-       if (len > dev->unique_len)
+       if (len > master->unique_len)
                DRM_ERROR("buffer overflow");
 
        dev->devname =
-           drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len +
+           drm_alloc(strlen(dev->driver->pci_driver.name) + master->unique_len +
                      2, DRM_MEM_DRIVER);
        if (dev->devname == NULL)
                return -ENOMEM;
 
        sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
-               dev->unique);
+               master->unique);
 
        return 0;
 }
@@ -275,7 +279,7 @@ int drm_getstats(struct drm_device *dev, void *data,
        for (i = 0; i < dev->counters; i++) {
                if (dev->types[i] == _DRM_STAT_LOCK)
                        stats->data[i].value =
-                           (dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0);
+                           (file_priv->master->lock.hw_lock ? file_priv->master->lock.hw_lock->lock : 0);
                else
                        stats->data[i].value = atomic_read(&dev->counts[i]);
                stats->data[i].type = dev->types[i];
@@ -317,7 +321,7 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri
                        /*
                         * Version 1.1 includes tying of DRM to specific device
                         */
-                       drm_set_busid(dev);
+                       drm_set_busid(dev, file_priv);
                }
        }
 
index 592ea2a..7dddbe1 100644 (file)
@@ -212,7 +212,7 @@ int drm_irq_install(struct drm_device * dev)
 
        if (dev->irq_enabled) {
                mutex_unlock(&dev->struct_mutex);
-               return -EBUSY;
+               return 0;
        }
        dev->irq_enabled = 1;
        mutex_unlock(&dev->struct_mutex);
@@ -261,6 +261,9 @@ int drm_irq_uninstall(struct drm_device * dev)
        if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                return -EINVAL;
 
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               return 0;
+
        mutex_lock(&dev->struct_mutex);
        irq_enabled = dev->irq_enabled;
        dev->irq_enabled = 0;
@@ -306,6 +309,8 @@ int drm_control(struct drm_device *dev, void *data,
        case DRM_INST_HANDLER:
                if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
                        return 0;
+               if (drm_core_check_feature(dev, DRIVER_MODESET))
+                       return 0;
                if (dev->if_version < DRM_IF_VERSION(1, 2) &&
                    ctl->irq != dev->irq)
                        return -EINVAL;
@@ -672,18 +677,18 @@ static void drm_locked_tasklet_func(unsigned long data)
        spin_lock_irqsave(&dev->tasklet_lock, irqflags);
 
        if (!dev->locked_tasklet_func ||
-           !drm_lock_take(&dev->lock,
+           !drm_lock_take(&dev->primary->master->lock,
                           DRM_KERNEL_CONTEXT)) {
                spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
                return;
        }
 
-       dev->lock.lock_time = jiffies;
+       dev->primary->master->lock.lock_time = jiffies;
        atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
 
        dev->locked_tasklet_func(dev);
 
-       drm_lock_free(&dev->lock,
+       drm_lock_free(&dev->primary->master->lock,
                      DRM_KERNEL_CONTEXT);
 
        dev->locked_tasklet_func = NULL;
index b8e4a5d..08e063d 100644 (file)
@@ -52,6 +52,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        DECLARE_WAITQUEUE(entry, current);
        struct drm_lock *lock = data;
+       struct drm_master *master = file_priv->master;
        int ret = 0;
 
        ++file_priv->lock_count;
@@ -64,26 +65,26 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 
        DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
                  lock->context, current->pid,
-                 dev->lock.hw_lock->lock, lock->flags);
+                 master->lock.hw_lock->lock, lock->flags);
 
        if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE))
                if (lock->context < 0)
                        return -EINVAL;
 
-       add_wait_queue(&dev->lock.lock_queue, &entry);
-       spin_lock(&dev->lock.spinlock);
-       dev->lock.user_waiters++;
-       spin_unlock(&dev->lock.spinlock);
+       add_wait_queue(&master->lock.lock_queue, &entry);
+       spin_lock(&master->lock.spinlock);
+       master->lock.user_waiters++;
+       spin_unlock(&master->lock.spinlock);
        for (;;) {
                __set_current_state(TASK_INTERRUPTIBLE);
-               if (!dev->lock.hw_lock) {
+               if (!master->lock.hw_lock) {
                        /* Device has been unregistered */
                        ret = -EINTR;
                        break;
                }
-               if (drm_lock_take(&dev->lock, lock->context)) {
-                       dev->lock.file_priv = file_priv;
-                       dev->lock.lock_time = jiffies;
+               if (drm_lock_take(&master->lock, lock->context)) {
+                       master->lock.file_priv = file_priv;
+                       master->lock.lock_time = jiffies;
                        atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
                        break;  /* Got lock */
                }
@@ -95,11 +96,11 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
                        break;
                }
        }
-       spin_lock(&dev->lock.spinlock);
-       dev->lock.user_waiters--;
-       spin_unlock(&dev->lock.spinlock);
+       spin_lock(&master->lock.spinlock);
+       master->lock.user_waiters--;
+       spin_unlock(&master->lock.spinlock);
        __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&dev->lock.lock_queue, &entry);
+       remove_wait_queue(&master->lock.lock_queue, &entry);
 
        DRM_DEBUG("%d %s\n", lock->context,
                  ret ? "interrupted" : "has lock");
@@ -111,7 +112,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
        sigaddset(&dev->sigmask, SIGTTIN);
        sigaddset(&dev->sigmask, SIGTTOU);
        dev->sigdata.context = lock->context;
-       dev->sigdata.lock = dev->lock.hw_lock;
+       dev->sigdata.lock = master->lock.hw_lock;
        block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
 
        if (dev->driver->dma_ready && (lock->flags & _DRM_LOCK_READY))
@@ -149,6 +150,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        struct drm_lock *lock = data;
+       struct drm_master *master = file_priv->master;
        unsigned long irqflags;
 
        if (lock->context == DRM_KERNEL_CONTEXT) {
@@ -175,7 +177,7 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
        if (dev->driver->kernel_context_switch_unlock)
                dev->driver->kernel_context_switch_unlock(dev);
        else {
-               if (drm_lock_free(&dev->lock,lock->context)) {
+               if (drm_lock_free(&master->lock,lock->context)) {
                        /* FIXME: Should really bail out here. */
                }
        }
@@ -384,10 +386,10 @@ EXPORT_SYMBOL(drm_idlelock_release);
 
 int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv)
 {
-
-       return (file_priv->lock_count && dev->lock.hw_lock &&
-               _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
-               dev->lock.file_priv == file_priv);
+       struct drm_master *master = file_priv->master;
+       return (file_priv->lock_count && master->lock.hw_lock &&
+               _DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) &&
+               master->lock.file_priv == file_priv);
 }
 
 EXPORT_SYMBOL(drm_i_have_hw_lock);
index 5911029..28726a6 100644 (file)
@@ -294,3 +294,18 @@ void drm_mm_takedown(struct drm_mm * mm)
 }
 
 EXPORT_SYMBOL(drm_mm_takedown);
+
+void drm_mm_print(struct drm_mm *mm, const char *name)
+{
+       struct list_head *list;
+       const struct list_head *mm_stack = &mm->ml_entry;
+       struct drm_mm_node *entry;
+
+       DRM_DEBUG("Memory usage for '%s'\n", name ? name : "unknown");
+       list_for_each(list, mm_stack) {
+               entry = list_entry(list, struct drm_mm_node, ml_entry);
+               DRM_DEBUG("\t0x%08lx %li %s pages\n", entry->start, entry->size,
+                       entry->free ? "free" : "used");
+       }
+}
+EXPORT_SYMBOL(drm_mm_print);
diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c
new file mode 100644 (file)
index 0000000..3763ca6
--- /dev/null
@@ -0,0 +1,560 @@
+/*
+ * Copyright Â© 1997-2003 by The XFree86 Project, Inc.
+ *
+ * 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
+ * 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 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+/*
+ * Copyright Â© 2007 Dave Airlie
+ */
+
+#include <linux/list.h>
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+
+/**
+ * drm_mode_debug_printmodeline - debug print a mode
+ * @dev: DRM device
+ * @mode: mode to print
+ *
+ * LOCKING:
+ * None.
+ *
+ * Describe @mode using DRM_DEBUG.
+ */
+void drm_mode_debug_printmodeline(struct drm_device *dev,
+                                 struct drm_display_mode *mode)
+{
+       DRM_DEBUG("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
+                 mode->mode_id, mode->name, mode->vrefresh, mode->clock,
+                 mode->hdisplay, mode->hsync_start,
+                 mode->hsync_end, mode->htotal,
+                 mode->vdisplay, mode->vsync_start,
+                 mode->vsync_end, mode->vtotal, mode->type, mode->flags);
+}
+EXPORT_SYMBOL(drm_mode_debug_printmodeline);
+
+/**
+ * drm_mode_set_name - set the name on a mode
+ * @mode: name will be set in this mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Set the name of @mode to a standard format.
+ */
+void drm_mode_set_name(struct drm_display_mode *mode)
+{
+       snprintf(mode->name, DRM_DISPLAY_MODE_LEN, "%dx%d", mode->hdisplay,
+                mode->vdisplay);
+}
+EXPORT_SYMBOL(drm_mode_set_name);
+
+/**
+ * drm_mode_list_concat - move modes from one list to another
+ * @head: source list
+ * @new: dst list
+ *
+ * LOCKING:
+ * Caller must ensure both lists are locked.
+ *
+ * Move all the modes from @head to @new.
+ */
+void drm_mode_list_concat(struct list_head *head, struct list_head *new)
+{
+
+       struct list_head *entry, *tmp;
+
+       list_for_each_safe(entry, tmp, head) {
+               list_move_tail(entry, new);
+       }
+}
+
+/**
+ * drm_mode_width - get the width of a mode
+ * @mode: mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Return @mode's width (hdisplay) value.
+ *
+ * FIXME: is this needed?
+ *
+ * RETURNS:
+ * @mode->hdisplay
+ */
+int drm_mode_width(struct drm_display_mode *mode)
+{
+       return mode->hdisplay;
+
+}
+EXPORT_SYMBOL(drm_mode_width);
+
+/**
+ * drm_mode_height - get the height of a mode
+ * @mode: mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Return @mode's height (vdisplay) value.
+ *
+ * FIXME: is this needed?
+ *
+ * RETURNS:
+ * @mode->vdisplay
+ */
+int drm_mode_height(struct drm_display_mode *mode)
+{
+       return mode->vdisplay;
+}
+EXPORT_SYMBOL(drm_mode_height);
+
+/**
+ * drm_mode_vrefresh - get the vrefresh of a mode
+ * @mode: mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Return @mode's vrefresh rate or calculate it if necessary.
+ *
+ * FIXME: why is this needed?  shouldn't vrefresh be set already?
+ *
+ * RETURNS:
+ * Vertical refresh rate of @mode x 1000. For precision reasons.
+ */
+int drm_mode_vrefresh(struct drm_display_mode *mode)
+{
+       int refresh = 0;
+       unsigned int calc_val;
+
+       if (mode->vrefresh > 0)
+               refresh = mode->vrefresh;
+       else if (mode->htotal > 0 && mode->vtotal > 0) {
+               /* work out vrefresh the value will be x1000 */
+               calc_val = (mode->clock * 1000);
+
+               calc_val /= mode->htotal;
+               calc_val *= 1000;
+               calc_val /= mode->vtotal;
+
+               refresh = calc_val;
+               if (mode->flags & V_INTERLACE)
+                       refresh *= 2;
+               if (mode->flags & V_DBLSCAN)
+                       refresh /= 2;
+               if (mode->vscan > 1)
+                       refresh /= mode->vscan;
+       }
+       return refresh;
+}
+EXPORT_SYMBOL(drm_mode_vrefresh);
+       
+/**
+ * drm_mode_set_crtcinfo - set CRTC modesetting parameters
+ * @p: mode
+ * @adjust_flags: unused? (FIXME)
+ *
+ * LOCKING:
+ * None.
+ *
+ * Setup the CRTC modesetting parameters for @p, adjusting if necessary.
+ */
+void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
+{
+       if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN))
+               return;
+
+       p->crtc_hdisplay = p->hdisplay;
+       p->crtc_hsync_start = p->hsync_start;
+       p->crtc_hsync_end = p->hsync_end;
+       p->crtc_htotal = p->htotal;
+       p->crtc_hskew = p->hskew;
+       p->crtc_vdisplay = p->vdisplay;
+       p->crtc_vsync_start = p->vsync_start;
+       p->crtc_vsync_end = p->vsync_end;
+       p->crtc_vtotal = p->vtotal;
+
+       if (p->flags & V_INTERLACE) {
+               if (adjust_flags & CRTC_INTERLACE_HALVE_V) {
+                       p->crtc_vdisplay /= 2;
+                       p->crtc_vsync_start /= 2;
+                       p->crtc_vsync_end /= 2;
+                       p->crtc_vtotal /= 2;
+               }
+
+               p->crtc_vtotal |= 1;
+       }
+
+       if (p->flags & V_DBLSCAN) {
+               p->crtc_vdisplay *= 2;
+               p->crtc_vsync_start *= 2;
+               p->crtc_vsync_end *= 2;
+               p->crtc_vtotal *= 2;
+       }
+
+       if (p->vscan > 1) {
+               p->crtc_vdisplay *= p->vscan;
+               p->crtc_vsync_start *= p->vscan;
+               p->crtc_vsync_end *= p->vscan;
+               p->crtc_vtotal *= p->vscan;
+       }
+
+       p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay);
+       p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal);
+       p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay);
+       p->crtc_hblank_end = max(p->crtc_hsync_end, p->crtc_htotal);
+
+       p->crtc_hadjusted = false;
+       p->crtc_vadjusted = false;
+}
+EXPORT_SYMBOL(drm_mode_set_crtcinfo);
+
+
+/**
+ * drm_mode_duplicate - allocate and duplicate an existing mode
+ * @m: mode to duplicate
+ *
+ * LOCKING:
+ * None.
+ *
+ * Just allocate a new mode, copy the existing mode into it, and return
+ * a pointer to it.  Used to create new instances of established modes.
+ */
+struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
+                                           struct drm_display_mode *mode)
+{
+       struct drm_display_mode *nmode;
+       int new_id;
+
+       nmode = drm_mode_create(dev);
+       if (!nmode)
+               return NULL;
+
+       new_id = nmode->mode_id;
+       *nmode = *mode;
+       nmode->mode_id = new_id;
+       INIT_LIST_HEAD(&nmode->head);
+       return nmode;
+}
+EXPORT_SYMBOL(drm_mode_duplicate);
+
+/**
+ * drm_mode_equal - test modes for equality
+ * @mode1: first mode
+ * @mode2: second mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Check to see if @mode1 and @mode2 are equivalent.
+ *
+ * RETURNS:
+ * True if the modes are equal, false otherwise.
+ */
+bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2)
+{
+       if (mode1->clock == mode2->clock &&
+           mode1->hdisplay == mode2->hdisplay &&
+           mode1->hsync_start == mode2->hsync_start &&
+           mode1->hsync_end == mode2->hsync_end &&
+           mode1->htotal == mode2->htotal &&
+           mode1->hskew == mode2->hskew &&
+           mode1->vdisplay == mode2->vdisplay &&
+           mode1->vsync_start == mode2->vsync_start &&
+           mode1->vsync_end == mode2->vsync_end &&
+           mode1->vtotal == mode2->vtotal &&
+           mode1->vscan == mode2->vscan &&
+           mode1->flags == mode2->flags)
+               return true;
+       
+       return false;
+}
+EXPORT_SYMBOL(drm_mode_equal);
+
+/**
+ * drm_mode_validate_size - make sure modes adhere to size constraints
+ * @dev: DRM device
+ * @mode_list: list of modes to check
+ * @maxX: maximum width
+ * @maxY: maximum height
+ * @maxPitch: max pitch
+ *
+ * LOCKING:
+ * Caller must hold a lock protecting @mode_list.
+ *
+ * The DRM device (@dev) has size and pitch limits.  Here we validate the
+ * modes we probed for @dev against those limits and set their status as
+ * necessary.
+ */
+void drm_mode_validate_size(struct drm_device *dev,
+                           struct list_head *mode_list,
+                           int maxX, int maxY, int maxPitch)
+{
+       struct drm_display_mode *mode;
+
+       list_for_each_entry(mode, mode_list, head) {
+               if (maxPitch > 0 && mode->hdisplay > maxPitch)
+                       mode->status = MODE_BAD_WIDTH;
+               
+               if (maxX > 0 && mode->hdisplay > maxX)
+                       mode->status = MODE_VIRTUAL_X;
+
+               if (maxY > 0 && mode->vdisplay > maxY)
+                       mode->status = MODE_VIRTUAL_Y;
+       }
+}
+EXPORT_SYMBOL(drm_mode_validate_size);
+
+/**
+ * drm_mode_validate_clocks - validate modes against clock limits
+ * @dev: DRM device
+ * @mode_list: list of modes to check
+ * @min: minimum clock rate array
+ * @max: maximum clock rate array
+ * @n_ranges: number of clock ranges (size of arrays)
+ *
+ * LOCKING:
+ * Caller must hold a lock protecting @mode_list.
+ *
+ * Some code may need to check a mode list against the clock limits of the
+ * device in question.  This function walks the mode list, testing to make
+ * sure each mode falls within a given range (defined by @min and @max
+ * arrays) and sets @mode->status as needed.
+ */
+void drm_mode_validate_clocks(struct drm_device *dev,
+                             struct list_head *mode_list,
+                             int *min, int *max, int n_ranges)
+{
+       struct drm_display_mode *mode;
+       int i;
+
+       list_for_each_entry(mode, mode_list, head) {
+               bool good = false;
+               for (i = 0; i < n_ranges; i++) {
+                       if (mode->clock >= min[i] && mode->clock <= max[i]) {
+                               good = true;
+                               break;
+                       }
+               }
+               if (!good)
+                       mode->status = MODE_CLOCK_RANGE;
+       }
+}
+EXPORT_SYMBOL(drm_mode_validate_clocks);
+
+/**
+ * drm_mode_prune_invalid - remove invalid modes from mode list
+ * @dev: DRM device
+ * @mode_list: list of modes to check
+ * @verbose: be verbose about it
+ *
+ * LOCKING:
+ * Caller must hold a lock protecting @mode_list.
+ *
+ * Once mode list generation is complete, a caller can use this routine to
+ * remove invalid modes from a mode list.  If any of the modes have a
+ * status other than %MODE_OK, they are removed from @mode_list and freed.
+ */
+void drm_mode_prune_invalid(struct drm_device *dev,
+                           struct list_head *mode_list, bool verbose)
+{
+       struct drm_display_mode *mode, *t;
+
+       list_for_each_entry_safe(mode, t, mode_list, head) {
+               if (mode->status != MODE_OK) {
+                       list_del(&mode->head);
+                       if (verbose) {
+                               drm_mode_debug_printmodeline(dev, mode);
+                               DRM_DEBUG("Not using %s mode %d\n", mode->name, mode->status);
+                       }
+                       kfree(mode);
+               }
+       }
+}
+
+/**
+ * drm_mode_compare - compare modes for favorability
+ * @lh_a: list_head for first mode
+ * @lh_b: list_head for second mode
+ *
+ * LOCKING:
+ * None.
+ *
+ * Compare two modes, given by @lh_a and @lh_b, returning a value indicating
+ * which is better.
+ *
+ * RETURNS:
+ * Negative if @lh_a is better than @lh_b, zero if they're equivalent, or
+ * positive if @lh_b is better than @lh_a.
+ */
+static int drm_mode_compare(struct list_head *lh_a, struct list_head *lh_b)
+{
+       struct drm_display_mode *a = list_entry(lh_a, struct drm_display_mode, head);
+       struct drm_display_mode *b = list_entry(lh_b, struct drm_display_mode, head);
+       int diff;
+
+       diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) -
+               ((a->type & DRM_MODE_TYPE_PREFERRED) != 0);
+       if (diff)
+               return diff;
+       diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay;
+       if (diff)
+               return diff;
+       diff = b->clock - a->clock;
+       return diff;
+}
+
+/* FIXME: what we don't have a list sort function? */
+/* list sort from Mark J Roberts (mjr@znex.org) */
+void list_sort(struct list_head *head, int (*cmp)(struct list_head *a, struct list_head *b))
+{
+       struct list_head *p, *q, *e, *list, *tail, *oldhead;
+       int insize, nmerges, psize, qsize, i;
+       
+       list = head->next;
+       list_del(head);
+       insize = 1;
+       for (;;) {
+               p = oldhead = list;
+               list = tail = NULL;
+               nmerges = 0;
+               
+               while (p) {
+                       nmerges++;
+                       q = p;
+                       psize = 0;
+                       for (i = 0; i < insize; i++) {
+                               psize++;
+                               q = q->next == oldhead ? NULL : q->next;
+                               if (!q)
+                                       break;
+                       }
+                       
+                       qsize = insize;
+                       while (psize > 0 || (qsize > 0 && q)) {
+                               if (!psize) {
+                                       e = q;
+                                       q = q->next;
+                                       qsize--;
+                                       if (q == oldhead)
+                                               q = NULL;
+                               } else if (!qsize || !q) {
+                                       e = p;
+                                       p = p->next;
+                                       psize--;
+                                       if (p == oldhead)
+                                               p = NULL;
+                               } else if (cmp(p, q) <= 0) {
+                                       e = p;
+                                       p = p->next;
+                                       psize--;
+                                       if (p == oldhead)
+                                               p = NULL;
+                               } else {
+                                       e = q;
+                                       q = q->next;
+                                       qsize--;
+                                       if (q == oldhead)
+                                               q = NULL;
+                               }
+                               if (tail)
+                                       tail->next = e;
+                               else
+                                       list = e;
+                               e->prev = tail;
+                               tail = e;
+                       }
+                       p = q;
+               }
+               
+               tail->next = list;
+               list->prev = tail;
+               
+               if (nmerges <= 1)
+                       break;
+               
+               insize *= 2;
+       }
+       
+       head->next = list;
+       head->prev = list->prev;
+       list->prev->next = head;
+       list->prev = head;
+}
+
+/**
+ * drm_mode_sort - sort mode list
+ * @mode_list: list to sort
+ *
+ * LOCKING:
+ * Caller must hold a lock protecting @mode_list.
+ *
+ * Sort @mode_list by favorability, putting good modes first.
+ */
+void drm_mode_sort(struct list_head *mode_list)
+{
+       list_sort(mode_list, drm_mode_compare);
+}
+
+
+/**
+ * drm_mode_output_list_update - update the mode list for the output
+ * @output: the output to update
+ *
+ * LOCKING:
+ * Caller must hold a lock protecting @mode_list.
+ *
+ * This moves the modes from the @output probed_modes list
+ * to the actual mode list. It compares the probed mode against the current
+ * list and only adds different modes. All modes unverified after this point
+ * will be removed by the prune invalid modes.
+ */
+void drm_mode_output_list_update(struct drm_output *output)
+{
+       struct drm_display_mode *mode;
+       struct drm_display_mode *pmode, *pt;
+       int found_it;
+       list_for_each_entry_safe(pmode, pt, &output->probed_modes,
+                                head) {
+               found_it = 0;
+               /* go through current modes checking for the new probed mode */
+               list_for_each_entry(mode, &output->modes, head) {
+                       if (drm_mode_equal(pmode, mode)) {
+                               found_it = 1;
+                               /* if equal delete the probed mode */
+                               mode->status = pmode->status;
+                               list_del(&pmode->head);
+                               kfree(pmode);
+                               break;
+                       }
+               }
+
+               if (!found_it) {
+                       list_move_tail(&pmode->head, &output->modes);
+               }
+       }
+}
index 69e3f67..8f81b66 100644 (file)
@@ -156,7 +156,6 @@ struct drm_fence_object {
 };
 
 #define _DRM_FENCE_CLASSES 8
-#define _DRM_FENCE_TYPE_EXE 0x00
 
 struct drm_fence_class_manager {
        struct list_head ring;
@@ -639,12 +638,12 @@ struct drm_bo_driver {
 /*
  * buffer objects (drm_bo.c)
  */
-
 extern int drm_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);
 extern int drm_bo_destroy_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);
 extern int drm_bo_map_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);
 extern int drm_bo_unmap_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);
 extern int drm_bo_reference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int drm_bo_set_pin(struct drm_device *dev, struct drm_buffer_object *bo, int pin);
 extern int drm_bo_unreference_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);
 extern int drm_bo_wait_idle_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);
 extern int drm_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv);
@@ -786,6 +785,10 @@ extern void drm_regs_init(struct drm_reg_manager *manager,
                                              const void *),
                          void (*reg_destroy)(struct drm_reg *));
 
+extern int drm_mem_reg_ioremap(struct drm_device *dev, struct drm_bo_mem_reg * mem,
+                              void **virtual);
+extern void drm_mem_reg_iounmap(struct drm_device *dev, struct drm_bo_mem_reg * mem,
+                               void *virtual);
 /*
  * drm_bo_lock.c
  * Simple replacement for the hardware lock on buffer manager init and clean.
index 67afee8..e10501f 100644 (file)
@@ -166,6 +166,7 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request,
                         int *eof, void *data)
 {
        struct drm_minor *minor = (struct drm_minor *) data; 
+       struct drm_master *master = minor->master;
        struct drm_device *dev = minor->dev;
        int len = 0;
 
@@ -177,10 +178,10 @@ static int drm_name_info(char *buf, char **start, off_t offset, int request,
        *start = &buf[offset];
        *eof = 0;
 
-       if (dev->unique) {
+       if (master->unique) {
                DRM_PROC_PRINT("%s %s %s\n",
                               dev->driver->pci_driver.name,
-                              pci_name(dev->pdev), dev->unique);
+                              pci_name(dev->pdev), master->unique);
        } else {
                DRM_PROC_PRINT("%s %s\n", dev->driver->pci_driver.name,
                               pci_name(dev->pdev));
index 6584f51..ba13e5e 100644 (file)
@@ -58,6 +58,14 @@ static int drm_minor_get_id(struct drm_device *dev, int type)
        int ret;
        int base = 0, limit = 63;
 
+       if (type == DRM_MINOR_CONTROL) {
+               base += 64;
+               limit = base + 127;
+       } else if (type == DRM_MINOR_RENDER) {
+               base += 128;
+               limit = base + 255;
+       }       
+
 again:
        if (idr_pre_get(&drm_minors_idr, GFP_KERNEL) == 0) {
                DRM_ERROR("Out of memory expanding drawable idr\n");
@@ -80,21 +88,76 @@ again:
        return new_id;
 }
 
+struct drm_master *drm_get_master(struct drm_minor *minor)
+{
+       struct drm_master *master;
+
+       master = drm_calloc(1, sizeof(*master), DRM_MEM_DRIVER);
+       if (!master)
+               return NULL;
+
+//     INIT_LIST_HEAD(&master->filelist);
+       spin_lock_init(&master->lock.spinlock);
+       init_waitqueue_head(&master->lock.lock_queue);
+       drm_ht_create(&master->magiclist, DRM_MAGIC_HASH_ORDER);
+       INIT_LIST_HEAD(&master->magicfree);
+       master->minor = minor;
+
+       list_add_tail(&master->head, &minor->master_list);
+
+       return master;
+}
+
+void drm_put_master(struct drm_master *master)
+{
+       struct drm_magic_entry *pt, *next;
+       struct drm_device *dev = master->minor->dev;
+
+       list_del(&master->head);
+
+       if (dev->driver->master_destroy)
+               dev->driver->master_destroy(dev, master);
+
+       if (master->unique) {
+               drm_free(master->unique, strlen(master->unique) + 1, DRM_MEM_DRIVER);
+               master->unique = NULL;
+               master->unique_len = 0;
+       }
+
+       list_for_each_entry_safe(pt, next, &master->magicfree, head) {
+               list_del(&pt->head);
+               drm_ht_remove_item(&master->magiclist, &pt->hash_item);
+               drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+       }
+
+       drm_ht_remove(&master->magiclist);
+
+       if (master->lock.hw_lock) {
+               if (dev->sigdata.lock == master->lock.hw_lock)
+                       dev->sigdata.lock = NULL;
+               master->lock.hw_lock = NULL;    /* SHM removed */
+               master->lock.file_priv = NULL;
+               wake_up_interruptible(&master->lock.lock_queue);
+       }
+
+       drm_free(master, sizeof(*master), DRM_MEM_DRIVER);
+}
+
 static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
                           const struct pci_device_id *ent,
                           struct drm_driver *driver)
 {
        int retcode;
 
-       INIT_LIST_HEAD(&dev->filelist);
        INIT_LIST_HEAD(&dev->ctxlist);
        INIT_LIST_HEAD(&dev->vmalist);
        INIT_LIST_HEAD(&dev->maplist);
+       INIT_LIST_HEAD(&dev->filelist);
 
        spin_lock_init(&dev->count_lock);
        spin_lock_init(&dev->drw_lock);
        spin_lock_init(&dev->tasklet_lock);
-       spin_lock_init(&dev->lock.spinlock);
+//     spin_lock_init(&dev->lock.spinlock);
        init_timer(&dev->timer);
        mutex_init(&dev->struct_mutex);
        mutex_init(&dev->ctxlist_mutex);
@@ -112,9 +175,9 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
        dev->irq = pdev->irq;
        dev->irq_enabled = 0;
 
-       if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER)) {
+       if (drm_ht_create(&dev->map_hash, DRM_MAP_HASH_ORDER))
                return -ENOMEM;
-       }
+
        if (drm_mm_init(&dev->offset_manager, DRM_FILE_PAGE_OFFSET_START,
                        DRM_FILE_PAGE_OFFSET_SIZE)) {
                drm_ht_remove(&dev->map_hash);
@@ -157,11 +220,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
                }
        }
 
-       if (dev->driver->load)
-               if ((retcode = dev->driver->load(dev, ent->driver_data)))
-                       goto error_out_unreg;
-
-
        retcode = drm_ctxbitmap_init(dev);
        if (retcode) {
                DRM_ERROR("Cannot allocate memory for context bitmap.\n");
@@ -209,6 +267,7 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int t
        new_minor->device = MKDEV(DRM_MAJOR, minor_id);
        new_minor->dev = dev;
        new_minor->index = minor_id;
+       INIT_LIST_HEAD(&new_minor->master_list);
 
        idr_replace(&drm_minors_idr, new_minor, minor_id);
        
@@ -285,8 +344,16 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
        }
 
        /* only add the control node on a modesetting platform */
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               if ((ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL)))
+                       goto err_g3;
+
        if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY)))
-               goto err_g3;
+               goto err_g4;
+
+       if (dev->driver->load)
+               if ((ret = dev->driver->load(dev, ent->driver_data)))
+                       goto err_g5;
 
        if (dev->driver->load)
                if ((ret = dev->driver->load(dev, ent->driver_data)))
@@ -297,8 +364,11 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
                 driver->date, dev->primary->index);
 
        return 0;
-err_g4:
+err_g5:
        drm_put_minor(&dev->primary);
+err_g4:
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               drm_put_minor(&dev->control);
 err_g3:
        if (!drm_fb_loaded)
                pci_disable_device(pdev);
@@ -330,11 +400,6 @@ int drm_put_dev(struct drm_device * dev)
 {
        DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name);
 
-       if (dev->unique) {
-               drm_free(dev->unique, strlen(dev->unique) + 1, DRM_MEM_DRIVER);
-               dev->unique = NULL;
-               dev->unique_len = 0;
-       }
        if (dev->devname) {
                drm_free(dev->devname, strlen(dev->devname) + 1,
                         DRM_MEM_DRIVER);
index 3275942..3372a71 100644 (file)
@@ -36,8 +36,9 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
 
        printk(KERN_ERR "%s\n", __FUNCTION__);
 
-       if (drm_dev->driver->suspend)
-               return drm_dev->driver->suspend(drm_dev, state);
+       if (drm_minor->type == DRM_MINOR_CONTROL)
+               if (drm_dev->driver->suspend)
+                       return drm_dev->driver->suspend(drm_dev, state);
 
        return 0;
 }
@@ -54,8 +55,9 @@ static int drm_sysfs_resume(struct device *dev)
        struct drm_minor *drm_minor = to_drm_minor(dev);
        struct drm_device *drm_dev = drm_minor->dev;
 
-       if (drm_dev->driver->resume)
-               return drm_dev->driver->resume(drm_dev);
+       if (drm_minor->type == DRM_MINOR_CONTROL)
+               if (drm_dev->driver->resume)
+                       return drm_dev->driver->resume(drm_dev);
 
        return 0;
 }
@@ -167,7 +169,12 @@ int drm_sysfs_device_add(struct drm_minor *minor)
        minor->kdev.class = drm_class;
        minor->kdev.release = drm_sysfs_device_release;
        minor->kdev.devt = minor->device;
-       minor_str = "card%d";
+       if (minor->type == DRM_MINOR_CONTROL)
+               minor_str = "controlD%d";
+       else if (minor->type == DRM_MINOR_RENDER)
+               minor_str = "renderD%d";
+       else
+               minor_str = "card%d";
        
        snprintf(minor->kdev.bus_id, BUS_ID_SIZE, minor_str, minor->index);
 
index 0806747..ba58688 100644 (file)
@@ -89,7 +89,7 @@ int i915_init_mem_type(struct drm_device *dev, uint32_t type,
                man->drm_bus_maptype = _DRM_AGP;
                man->gpu_offset = 0;
                break;
-       case DRM_BO_MEM_PRIV0:
+       case DRM_BO_MEM_VRAM:
                if (!(drm_core_has_AGP(dev) && dev->agp)) {
                        DRM_ERROR("AGP is not enabled for memory type %u\n",
                                  (unsigned)type);
@@ -103,6 +103,9 @@ int i915_init_mem_type(struct drm_device *dev, uint32_t type,
                man->drm_bus_maptype = _DRM_AGP;
                man->gpu_offset = 0;
                break;
+       case DRM_BO_MEM_PRIV0: /* for OS preallocated space */
+               DRM_ERROR("PRIV0 not used yet.\n");
+               break;
        default:
                DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
                return -EINVAL;
@@ -139,7 +142,7 @@ static void i915_emit_copy_blit(struct drm_device * dev,
 {
        uint32_t cur_pages;
        uint32_t stride = PAGE_SIZE;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        RING_LOCALS;
 
        if (!dev_priv)
@@ -267,10 +270,12 @@ static inline void clflush(volatile void *__p)
 
 static inline void drm_cache_flush_addr(void *virt)
 {
+#ifdef cpu_has_clflush
        int i;
 
        for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size)
                clflush(virt+i);
+#endif
 }
 
 static inline void drm_cache_flush_page(struct page *p)
@@ -288,6 +293,9 @@ void i915_flush_ttm(struct drm_ttm *ttm)
        DRM_MEMORYBARRIER();
 
 #ifdef CONFIG_X86_32
+#ifndef cpu_has_clflush
+#define cpu_has_clflush 0
+#endif
        /* Hopefully nobody has built an x86-64 processor without clflush */
        if (!cpu_has_clflush) {
                wbinvd();
index e18bc8d..0e65c0c 100644 (file)
@@ -30,6 +30,7 @@
 #include "drmP.h"
 #include "drm.h"
 #include "i915_drm.h"
+#include "intel_drv.h"
 #include "i915_drv.h"
 
 #include "drm_pciids.h"
@@ -38,14 +39,17 @@ static struct pci_device_id pciidlist[] = {
        i915_PCI_IDS
 };
 
+unsigned int i915_modeset = 0;
+module_param_named(modeset, i915_modeset, int, 0400);
+
 #ifdef I915_HAVE_FENCE
 extern struct drm_fence_driver i915_fence_driver;
 #endif
 
 #ifdef I915_HAVE_BUFFER
 
-static uint32_t i915_mem_prios[] = {DRM_BO_MEM_PRIV0, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL};
-static uint32_t i915_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_PRIV0, DRM_BO_MEM_LOCAL};
+static uint32_t i915_mem_prios[] = {DRM_BO_MEM_VRAM, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL};
+static uint32_t i915_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_VRAM, DRM_BO_MEM_LOCAL};
 
 static struct drm_bo_driver i915_bo_driver = {
        .mem_type_prio = i915_mem_prios,
@@ -578,6 +582,11 @@ static struct drm_driver driver = {
        .reclaim_buffers = drm_core_reclaim_buffers,
        .get_map_ofs = drm_core_get_map_ofs,
        .get_reg_ofs = drm_core_get_reg_ofs,
+       .fb_probe = intelfb_probe,
+       .fb_remove = intelfb_remove,
+       .fb_resize = intelfb_resize,
+       .master_create = i915_master_create,
+       .master_destroy = i915_master_destroy,
        .ioctls = i915_ioctls,
        .fops = {
                .owner = THIS_MODULE,
@@ -619,6 +628,9 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 static int __init i915_init(void)
 {
        driver.num_ioctls = i915_max_ioctl;
+       if (i915_modeset == 1)
+               driver.driver_features |= DRIVER_MODESET;
+
        return drm_init(&driver, pciidlist);
 }
 
index de64a4f..0f6cdee 100644 (file)
@@ -94,7 +94,7 @@ static void i915_fence_flush(struct drm_device *dev,
 static void i915_fence_poll(struct drm_device *dev, uint32_t fence_class,
                            uint32_t waiting_types)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
        struct drm_fence_manager *fm = &dev->fm;
        struct drm_fence_class_manager *fc = &fm->fence_class[0];
        uint32_t sequence;
@@ -147,7 +147,7 @@ static int i915_fence_emit_sequence(struct drm_device *dev, uint32_t class,
                             uint32_t flags, uint32_t *sequence,
                             uint32_t *native_type)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
        if (unlikely(!dev_priv))
                return -EINVAL;
 
@@ -179,7 +179,7 @@ static int i915_fence_wait(struct drm_fence_object *fence,
                           int lazy, int interruptible, uint32_t mask)
 {
        struct drm_device *dev = fence->dev;
-       drm_i915_private_t *dev_priv = (struct drm_i915_private *) dev->dev_private;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
        struct drm_fence_manager *fm = &dev->fm;
        struct drm_fence_class_manager *fc = &fm->fence_class[0];
        int ret;
diff --git a/linux-core/i915_init.c b/linux-core/i915_init.c
new file mode 120000 (symlink)
index 0000000..473ddf7
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/i915_init.c
\ No newline at end of file
diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c
new file mode 100644 (file)
index 0000000..a9fb50a
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright Â© 2006-2007 Intel Corporation
+ *
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ */
+
+#include <linux/i2c.h>
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+static void intel_crt_dpms(struct drm_output *output, int mode)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 temp;
+       
+       temp = I915_READ(ADPA);
+       temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
+       temp &= ~ADPA_DAC_ENABLE;
+       
+       switch(mode) {
+       case DPMSModeOn:
+               temp |= ADPA_DAC_ENABLE;
+               break;
+       case DPMSModeStandby:
+               temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE;
+               break;
+       case DPMSModeSuspend:
+               temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE;
+               break;
+       case DPMSModeOff:
+               temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
+               break;
+       }
+       
+       I915_WRITE(ADPA, temp);
+}
+
+static void intel_crt_save(struct drm_output *output)
+{
+       
+}
+
+static void intel_crt_restore(struct drm_output *output)
+{
+
+}
+
+static int intel_crt_mode_valid(struct drm_output *output,
+                               struct drm_display_mode *mode)
+{
+       if (mode->flags & V_DBLSCAN)
+               return MODE_NO_DBLESCAN;
+
+       if (mode->clock > 400000 || mode->clock < 25000)
+               return MODE_CLOCK_RANGE;
+
+       return MODE_OK;
+}
+
+static bool intel_crt_mode_fixup(struct drm_output *output,
+                                struct drm_display_mode *mode,
+                                struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void intel_crt_mode_set(struct drm_output *output,
+                              struct drm_display_mode *mode,
+                              struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_crtc *crtc = output->crtc;
+       struct intel_crtc *intel_crtc = crtc->driver_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int dpll_md_reg;
+       u32 adpa, dpll_md;
+
+       if (intel_crtc->pipe == 0) 
+               dpll_md_reg = DPLL_A_MD;
+       else
+               dpll_md_reg = DPLL_B_MD;
+
+       /*
+        * Disable separate mode multiplier used when cloning SDVO to CRT
+        * XXX this needs to be adjusted when we really are cloning
+        */
+       if (IS_I965G(dev)) {
+               dpll_md = I915_READ(dpll_md_reg);
+               I915_WRITE(dpll_md_reg,
+                          dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
+       }
+       
+       adpa = 0;
+       if (adjusted_mode->flags & V_PHSYNC)
+               adpa |= ADPA_HSYNC_ACTIVE_HIGH;
+       if (adjusted_mode->flags & V_PVSYNC)
+               adpa |= ADPA_VSYNC_ACTIVE_HIGH;
+       
+       if (intel_crtc->pipe == 0)
+               adpa |= ADPA_PIPE_A_SELECT;
+       else
+               adpa |= ADPA_PIPE_B_SELECT;
+       
+       I915_WRITE(ADPA, adpa);
+}
+
+/**
+ * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect CRT presence.
+ *
+ * Only for I945G/GM.
+ *
+ * \return TRUE if CRT is connected.
+ * \return FALSE if CRT is disconnected.
+ */
+static bool intel_crt_detect_hotplug(struct drm_output *output)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 temp;
+#if 1
+       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+       temp = I915_READ(PORT_HOTPLUG_EN);
+
+       I915_WRITE(PORT_HOTPLUG_EN,
+                  temp | CRT_HOTPLUG_FORCE_DETECT | (1 << 5));
+
+       do {
+               if (!(I915_READ(PORT_HOTPLUG_EN) & CRT_HOTPLUG_FORCE_DETECT))
+                       break;
+               msleep(1);
+       } while (time_after(timeout, jiffies));
+
+       if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) ==
+           CRT_HOTPLUG_MONITOR_COLOR)
+               return true;
+
+       return false;
+#else
+       temp = I915_READ(PORT_HOTPLUG_STAT);
+       DRM_DEBUG("HST 0x%08x\n", temp);
+
+       if (temp & (1 << 8) && temp & (1 << 9))
+               return true;
+
+       return false;
+#endif
+}
+
+static bool intel_crt_detect_ddc(struct drm_output *output)
+{
+       struct intel_output *intel_output = output->driver_private;
+
+       /* CRT should always be at 0, but check anyway */
+       if (intel_output->type != INTEL_OUTPUT_ANALOG)
+               return false;
+       
+       return intel_ddc_probe(output);
+}
+
+static enum drm_output_status intel_crt_detect(struct drm_output *output)
+{
+       struct drm_device *dev = output->dev;
+       
+       if (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev)) {
+               if (intel_crt_detect_hotplug(output))
+                       return output_status_connected;
+               else
+                       return output_status_disconnected;
+       }
+
+       if (intel_crt_detect_ddc(output))
+               return output_status_connected;
+
+       /* TODO use load detect */
+       return output_status_unknown;
+}
+
+static void intel_crt_destroy(struct drm_output *output)
+{
+       struct intel_output *intel_output = output->driver_private;
+
+       intel_i2c_destroy(intel_output->ddc_bus);
+       kfree(output->driver_private);
+}
+
+static int intel_crt_get_modes(struct drm_output *output)
+{
+       return intel_ddc_get_modes(output);
+}
+
+static bool intel_crt_set_property(struct drm_output *output,
+                                 struct drm_property *property,
+                                 uint64_t value)
+{
+       struct drm_device *dev = output->dev;
+
+       if (property == dev->mode_config.dpms_property)
+               intel_crt_dpms(output, (uint32_t)(value & 0xf));
+
+       return true;
+}
+
+/*
+ * Routines for controlling stuff on the analog port
+ */
+static const struct drm_output_funcs intel_crt_output_funcs = {
+       .dpms = intel_crt_dpms,
+       .save = intel_crt_save,
+       .restore = intel_crt_restore,
+       .mode_valid = intel_crt_mode_valid,
+       .mode_fixup = intel_crt_mode_fixup,
+       .prepare = intel_output_prepare,
+       .mode_set = intel_crt_mode_set,
+       .commit = intel_output_commit,
+       .detect = intel_crt_detect,
+       .get_modes = intel_crt_get_modes,
+       .cleanup = intel_crt_destroy,
+       .set_property = intel_crt_set_property,
+};
+
+void intel_crt_init(struct drm_device *dev)
+{
+       struct drm_output *output;
+       struct intel_output *intel_output;
+
+       output = drm_output_create(dev, &intel_crt_output_funcs,
+                                  DRM_MODE_OUTPUT_DAC);
+
+       intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL);
+       if (!intel_output) {
+               drm_output_destroy(output);
+               return;
+       }
+       /* Set up the DDC bus. */
+       intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A");
+       if (!intel_output->ddc_bus) {
+               dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
+                          "failed.\n");
+               return;
+       }
+
+       intel_output->type = INTEL_OUTPUT_ANALOG;
+       output->driver_private = intel_output;
+       output->interlace_allowed = 0;
+       output->doublescan_allowed = 0;
+
+       drm_output_attach_property(output, dev->mode_config.connector_type_property, ConnectorVGA);
+}
diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c
new file mode 100644 (file)
index 0000000..4b48a0b
--- /dev/null
@@ -0,0 +1,1366 @@
+/*
+ * Copyright Â© 2006-2007 Intel Corporation
+ *
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ */
+
+#include <linux/i2c.h>
+#include "drmP.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
+
+typedef struct {
+    /* given values */    
+    int n;
+    int m1, m2;
+    int p1, p2;
+    /* derived values */
+    int        dot;
+    int        vco;
+    int        m;
+    int        p;
+} intel_clock_t;
+
+typedef struct {
+    int        min, max;
+} intel_range_t;
+
+typedef struct {
+    int        dot_limit;
+    int        p2_slow, p2_fast;
+} intel_p2_t;
+
+#define INTEL_P2_NUM                 2
+
+typedef struct {
+    intel_range_t   dot, vco, n, m, m1, m2, p, p1;
+    intel_p2_t     p2;
+} intel_limit_t;
+
+#define I8XX_DOT_MIN             25000
+#define I8XX_DOT_MAX            350000
+#define I8XX_VCO_MIN            930000
+#define I8XX_VCO_MAX           1400000
+#define I8XX_N_MIN                   3
+#define I8XX_N_MAX                  16
+#define I8XX_M_MIN                  96
+#define I8XX_M_MAX                 140
+#define I8XX_M1_MIN                 18
+#define I8XX_M1_MAX                 26
+#define I8XX_M2_MIN                  6
+#define I8XX_M2_MAX                 16
+#define I8XX_P_MIN                   4
+#define I8XX_P_MAX                 128
+#define I8XX_P1_MIN                  2
+#define I8XX_P1_MAX                 33
+#define I8XX_P1_LVDS_MIN             1
+#define I8XX_P1_LVDS_MAX             6
+#define I8XX_P2_SLOW                 4
+#define I8XX_P2_FAST                 2
+#define I8XX_P2_LVDS_SLOW            14
+#define I8XX_P2_LVDS_FAST            14 /* No fast option */
+#define I8XX_P2_SLOW_LIMIT      165000
+
+#define I9XX_DOT_MIN             20000
+#define I9XX_DOT_MAX            400000
+#define I9XX_VCO_MIN           1400000
+#define I9XX_VCO_MAX           2800000
+#define I9XX_N_MIN                   3
+#define I9XX_N_MAX                   8
+#define I9XX_M_MIN                  70
+#define I9XX_M_MAX                 120
+#define I9XX_M1_MIN                 10
+#define I9XX_M1_MAX                 20
+#define I9XX_M2_MIN                  5
+#define I9XX_M2_MAX                  9
+#define I9XX_P_SDVO_DAC_MIN          5
+#define I9XX_P_SDVO_DAC_MAX         80
+#define I9XX_P_LVDS_MIN                      7
+#define I9XX_P_LVDS_MAX                     98
+#define I9XX_P1_MIN                  1
+#define I9XX_P1_MAX                  8
+#define I9XX_P2_SDVO_DAC_SLOW               10
+#define I9XX_P2_SDVO_DAC_FAST                5
+#define I9XX_P2_SDVO_DAC_SLOW_LIMIT     200000
+#define I9XX_P2_LVDS_SLOW                   14
+#define I9XX_P2_LVDS_FAST                    7
+#define I9XX_P2_LVDS_SLOW_LIMIT                 112000
+
+#define INTEL_LIMIT_I8XX_DVO_DAC    0
+#define INTEL_LIMIT_I8XX_LVDS      1
+#define INTEL_LIMIT_I9XX_SDVO_DAC   2
+#define INTEL_LIMIT_I9XX_LVDS      3
+
+static const intel_limit_t intel_limits[] = {
+    { /* INTEL_LIMIT_I8XX_DVO_DAC */
+        .dot = { .min = I8XX_DOT_MIN,          .max = I8XX_DOT_MAX },
+        .vco = { .min = I8XX_VCO_MIN,          .max = I8XX_VCO_MAX },
+        .n   = { .min = I8XX_N_MIN,            .max = I8XX_N_MAX },
+        .m   = { .min = I8XX_M_MIN,            .max = I8XX_M_MAX },
+        .m1  = { .min = I8XX_M1_MIN,           .max = I8XX_M1_MAX },
+        .m2  = { .min = I8XX_M2_MIN,           .max = I8XX_M2_MAX },
+        .p   = { .min = I8XX_P_MIN,            .max = I8XX_P_MAX },
+        .p1  = { .min = I8XX_P1_MIN,           .max = I8XX_P1_MAX },
+       .p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
+                .p2_slow = I8XX_P2_SLOW,       .p2_fast = I8XX_P2_FAST },
+    },
+    { /* INTEL_LIMIT_I8XX_LVDS */
+        .dot = { .min = I8XX_DOT_MIN,          .max = I8XX_DOT_MAX },
+        .vco = { .min = I8XX_VCO_MIN,          .max = I8XX_VCO_MAX },
+        .n   = { .min = I8XX_N_MIN,            .max = I8XX_N_MAX },
+        .m   = { .min = I8XX_M_MIN,            .max = I8XX_M_MAX },
+        .m1  = { .min = I8XX_M1_MIN,           .max = I8XX_M1_MAX },
+        .m2  = { .min = I8XX_M2_MIN,           .max = I8XX_M2_MAX },
+        .p   = { .min = I8XX_P_MIN,            .max = I8XX_P_MAX },
+        .p1  = { .min = I8XX_P1_LVDS_MIN,      .max = I8XX_P1_LVDS_MAX },
+       .p2  = { .dot_limit = I8XX_P2_SLOW_LIMIT,
+                .p2_slow = I8XX_P2_LVDS_SLOW,  .p2_fast = I8XX_P2_LVDS_FAST },
+    },
+    { /* INTEL_LIMIT_I9XX_SDVO_DAC */
+        .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX },
+        .vco = { .min = I9XX_VCO_MIN,          .max = I9XX_VCO_MAX },
+        .n   = { .min = I9XX_N_MIN,            .max = I9XX_N_MAX },
+        .m   = { .min = I9XX_M_MIN,            .max = I9XX_M_MAX },
+        .m1  = { .min = I9XX_M1_MIN,           .max = I9XX_M1_MAX },
+        .m2  = { .min = I9XX_M2_MIN,           .max = I9XX_M2_MAX },
+        .p   = { .min = I9XX_P_SDVO_DAC_MIN,   .max = I9XX_P_SDVO_DAC_MAX },
+        .p1  = { .min = I9XX_P1_MIN,           .max = I9XX_P1_MAX },
+       .p2  = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
+                .p2_slow = I9XX_P2_SDVO_DAC_SLOW,      .p2_fast = I9XX_P2_SDVO_DAC_FAST },
+    },
+    { /* INTEL_LIMIT_I9XX_LVDS */
+        .dot = { .min = I9XX_DOT_MIN,          .max = I9XX_DOT_MAX },
+        .vco = { .min = I9XX_VCO_MIN,          .max = I9XX_VCO_MAX },
+        .n   = { .min = I9XX_N_MIN,            .max = I9XX_N_MAX },
+        .m   = { .min = I9XX_M_MIN,            .max = I9XX_M_MAX },
+        .m1  = { .min = I9XX_M1_MIN,           .max = I9XX_M1_MAX },
+        .m2  = { .min = I9XX_M2_MIN,           .max = I9XX_M2_MAX },
+        .p   = { .min = I9XX_P_LVDS_MIN,       .max = I9XX_P_LVDS_MAX },
+        .p1  = { .min = I9XX_P1_MIN,           .max = I9XX_P1_MAX },
+       /* The single-channel range is 25-112Mhz, and dual-channel
+        * is 80-224Mhz.  Prefer single channel as much as possible.
+        */
+       .p2  = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
+                .p2_slow = I9XX_P2_LVDS_SLOW,  .p2_fast = I9XX_P2_LVDS_FAST },
+    },
+};
+
+static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       const intel_limit_t *limit;
+       
+       if (IS_I9XX(dev)) {
+               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+                       limit = &intel_limits[INTEL_LIMIT_I9XX_LVDS];
+               else
+                       limit = &intel_limits[INTEL_LIMIT_I9XX_SDVO_DAC];
+       } else {
+               if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+                       limit = &intel_limits[INTEL_LIMIT_I8XX_LVDS];
+               else
+                       limit = &intel_limits[INTEL_LIMIT_I8XX_DVO_DAC];
+       }
+       return limit;
+}
+
+/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */
+
+static void i8xx_clock(int refclk, intel_clock_t *clock)
+{
+       clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
+       clock->p = clock->p1 * clock->p2;
+       clock->vco = refclk * clock->m / (clock->n + 2);
+       clock->dot = clock->vco / clock->p;
+}
+
+/** Derive the pixel clock for the given refclk and divisors for 9xx chips. */
+
+static void i9xx_clock(int refclk, intel_clock_t *clock)
+{
+       clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
+       clock->p = clock->p1 * clock->p2;
+       clock->vco = refclk * clock->m / (clock->n + 2);
+       clock->dot = clock->vco / clock->p;
+}
+
+static void intel_clock(struct drm_device *dev, int refclk,
+                       intel_clock_t *clock)
+{
+       if (IS_I9XX(dev))
+               return i9xx_clock (refclk, clock);
+       else
+               return i8xx_clock (refclk, clock);
+}
+
+/**
+ * Returns whether any output on the specified pipe is of the specified type
+ */
+bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
+{
+    struct drm_device *dev = crtc->dev;
+    struct drm_mode_config *mode_config = &dev->mode_config;
+    struct drm_output *l_entry;
+
+    list_for_each_entry(l_entry, &mode_config->output_list, head) {
+           if (l_entry->crtc == crtc) {
+                   struct intel_output *intel_output = l_entry->driver_private;
+                   if (intel_output->type == type)
+                           return true;
+           }
+    }
+    return false;
+}
+
+#define INTELPllInvalid(s)   { /* ErrorF (s) */; return false; }
+/**
+ * Returns whether the given set of divisors are valid for a given refclk with
+ * the given outputs.
+ */
+
+static bool intel_PLL_is_valid(struct drm_crtc *crtc, intel_clock_t *clock)
+{
+       const intel_limit_t *limit = intel_limit (crtc);
+       
+       if (clock->p1  < limit->p1.min  || limit->p1.max  < clock->p1)
+               INTELPllInvalid ("p1 out of range\n");
+       if (clock->p   < limit->p.min   || limit->p.max   < clock->p)
+               INTELPllInvalid ("p out of range\n");
+       if (clock->m2  < limit->m2.min  || limit->m2.max  < clock->m2)
+               INTELPllInvalid ("m2 out of range\n");
+       if (clock->m1  < limit->m1.min  || limit->m1.max  < clock->m1)
+               INTELPllInvalid ("m1 out of range\n");
+       if (clock->m1 <= clock->m2)
+               INTELPllInvalid ("m1 <= m2\n");
+       if (clock->m   < limit->m.min   || limit->m.max   < clock->m)
+               INTELPllInvalid ("m out of range\n");
+       if (clock->n   < limit->n.min   || limit->n.max   < clock->n)
+               INTELPllInvalid ("n out of range\n");
+       if (clock->vco < limit->vco.min || limit->vco.max < clock->vco)
+               INTELPllInvalid ("vco out of range\n");
+       /* XXX: We may need to be checking "Dot clock" depending on the multiplier,
+        * output, etc., rather than just a single range.
+        */
+       if (clock->dot < limit->dot.min || limit->dot.max < clock->dot)
+               INTELPllInvalid ("dot out of range\n");
+       
+       return true;
+}
+
+/**
+ * Returns a set of divisors for the desired target clock with the given
+ * refclk, or FALSE.  The returned values represent the clock equation:
+ * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+ */
+static bool intel_find_best_PLL(struct drm_crtc *crtc, int target,
+                               int refclk, intel_clock_t *best_clock)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       intel_clock_t clock;
+       const intel_limit_t *limit = intel_limit(crtc);
+       int err = target;
+
+       if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+           (I915_READ(LVDS) & LVDS_PORT_EN) != 0) {
+               /*
+                * For LVDS, if the panel is on, just rely on its current
+                * settings for dual-channel.  We haven't figured out how to
+                * reliably set up different single/dual channel state, if we
+                * even can.
+                */
+               if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
+                   LVDS_CLKB_POWER_UP)
+                       clock.p2 = limit->p2.p2_fast;
+               else
+                       clock.p2 = limit->p2.p2_slow;
+       } else {
+               if (target < limit->p2.dot_limit)
+                       clock.p2 = limit->p2.p2_slow;
+               else
+                       clock.p2 = limit->p2.p2_fast;
+       }
+       
+       memset (best_clock, 0, sizeof (*best_clock));
+       
+       for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
+               for (clock.m2 = limit->m2.min; clock.m2 < clock.m1 &&
+                            clock.m2 <= limit->m2.max; clock.m2++) {
+                       for (clock.n = limit->n.min; clock.n <= limit->n.max;
+                            clock.n++) {
+                               for (clock.p1 = limit->p1.min;
+                                    clock.p1 <= limit->p1.max; clock.p1++) {
+                                       int this_err;
+                                       
+                                       intel_clock(dev, refclk, &clock);
+                                       
+                                       if (!intel_PLL_is_valid(crtc, &clock))
+                                               continue;
+                                       
+                                       this_err = abs(clock.dot - target);
+                                       if (this_err < err) {
+                                               *best_clock = clock;
+                                               err = this_err;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return (err != target);
+}
+
+void
+intel_set_vblank(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc;
+       struct intel_crtc *intel_crtc;
+       int vbl_pipe = 0;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               intel_crtc = crtc->driver_private;
+
+               if (crtc->enabled)
+                       vbl_pipe |= (1<<intel_crtc->pipe);
+       }
+
+       dev_priv->vblank_pipe = vbl_pipe;
+       i915_enable_interrupt(dev);
+}
+void
+intel_wait_for_vblank(struct drm_device *dev)
+{
+       /* Wait for 20ms, i.e. one cycle at 50hz. */
+       udelay(20000);
+}
+
+void
+intel_pipe_set_base(struct drm_crtc *crtc, int x, int y)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_master_private *master_priv;
+       struct intel_crtc *intel_crtc = crtc->driver_private;
+       int pipe = intel_crtc->pipe;
+       unsigned long Start, Offset;
+       int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE);
+       int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF);
+       int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
+       int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
+       u32 dspcntr;
+
+       /* no fb bound */
+       if (!crtc->fb) {
+               DRM_DEBUG("No FB bound\n");
+               return;
+       }
+
+       Start = crtc->fb->bo->offset;
+       Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8);
+
+       I915_WRITE(dspstride, crtc->fb->pitch);
+
+       dspcntr = I915_READ(dspcntr_reg);
+       switch (crtc->fb->bits_per_pixel) {
+       case 8:
+               dspcntr |= DISPPLANE_8BPP;
+               break;
+       case 16:
+               if (crtc->fb->depth == 15)
+                       dspcntr |= DISPPLANE_15_16BPP;
+               else
+                       dspcntr |= DISPPLANE_16BPP;
+               break;
+       case 24:
+       case 32:
+               dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
+               break;
+       default:
+               DRM_ERROR("Unknown color depth\n");
+               return;
+       }
+       I915_WRITE(dspcntr_reg, dspcntr);
+
+       DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y);
+       if (IS_I965G(dev)) {
+               I915_WRITE(dspbase, Offset);
+               I915_READ(dspbase);
+               I915_WRITE(dspsurf, Start);
+               I915_READ(dspsurf);
+       } else {
+               I915_WRITE(dspbase, Start + Offset);
+               I915_READ(dspbase);
+       }
+       
+
+       if (!dev->primary->master)
+               return;
+
+       master_priv = dev->primary->master->driver_priv;
+       if (!master_priv->sarea_priv) 
+               return;
+               
+       switch (pipe) {
+       case 0:
+               master_priv->sarea_priv->planeA_x = x;
+               master_priv->sarea_priv->planeA_y = y;
+               break;
+       case 1:
+               master_priv->sarea_priv->planeB_x = x;
+               master_priv->sarea_priv->planeB_y = y;
+               break;
+       default:
+               DRM_ERROR("Can't update pipe %d in SAREA\n", pipe);
+               break;
+       }
+}
+
+
+
+/**
+ * Sets the power management mode of the pipe and plane.
+ *
+ * This code should probably grow support for turning the cursor off and back
+ * on appropriately at the same time as we're turning the pipe off/on.
+ */
+static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_master_private *master_priv;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = crtc->driver_private;
+       int pipe = intel_crtc->pipe;
+       int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
+       int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
+       int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE;
+       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+       u32 temp;
+       bool enabled;
+
+       /* XXX: When our outputs are all unaware of DPMS modes other than off
+        * and on, we should map those modes to DPMSModeOff in the CRTC.
+        */
+       switch (mode) {
+       case DPMSModeOn:
+       case DPMSModeStandby:
+       case DPMSModeSuspend:
+               /* Enable the DPLL */
+               temp = I915_READ(dpll_reg);
+               if ((temp & DPLL_VCO_ENABLE) == 0) {
+                       I915_WRITE(dpll_reg, temp);
+                       I915_READ(dpll_reg);
+                       /* Wait for the clocks to stabilize. */
+                       udelay(150);
+                       I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
+                       I915_READ(dpll_reg);
+                       /* Wait for the clocks to stabilize. */
+                       udelay(150);
+                       I915_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
+                       I915_READ(dpll_reg);
+                       /* Wait for the clocks to stabilize. */
+                       udelay(150);
+               }
+               
+               /* Enable the pipe */
+               temp = I915_READ(pipeconf_reg);
+               if ((temp & PIPEACONF_ENABLE) == 0)
+                       I915_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
+               
+               /* Enable the plane */
+               temp = I915_READ(dspcntr_reg);
+               if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
+                       I915_WRITE(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
+                       /* Flush the plane changes */
+                       I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
+               }
+               
+               intel_crtc_load_lut(crtc);
+               
+               /* Give the overlay scaler a chance to enable if it's on this pipe */
+               //intel_crtc_dpms_video(crtc, TRUE); TODO
+       break;
+       case DPMSModeOff:
+               /* Give the overlay scaler a chance to disable if it's on this pipe */
+               //intel_crtc_dpms_video(crtc, FALSE); TODO
+               
+               /* Disable the VGA plane that we never use */
+               I915_WRITE(VGACNTRL, VGA_DISP_DISABLE);
+               
+               /* Disable display plane */
+               temp = I915_READ(dspcntr_reg);
+               if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
+                       I915_WRITE(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
+                       /* Flush the plane changes */
+                       I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
+                       I915_READ(dspbase_reg);
+               }
+               
+               if (!IS_I9XX(dev)) {
+                       /* Wait for vblank for the disable to take effect */
+                       intel_wait_for_vblank(dev);
+               }
+               
+               /* Next, disable display pipes */
+               temp = I915_READ(pipeconf_reg);
+               if ((temp & PIPEACONF_ENABLE) != 0) {
+                       I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
+                       I915_READ(pipeconf_reg);
+               }
+               
+               /* Wait for vblank for the disable to take effect. */
+               intel_wait_for_vblank(dev);
+               
+               temp = I915_READ(dpll_reg);
+               if ((temp & DPLL_VCO_ENABLE) != 0) {
+                       I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE);
+                       I915_READ(dpll_reg);
+               }
+               
+               /* Wait for the clocks to turn off. */
+               udelay(150);
+               break;
+       }
+
+       if (!dev->primary->master)
+               return; 
+
+       master_priv = dev->primary->master->driver_priv;
+       if (!master_priv->sarea_priv)
+               return;
+
+       enabled = crtc->enabled && mode != DPMSModeOff;
+       
+       switch (pipe) {
+       case 0:
+               master_priv->sarea_priv->planeA_w = enabled ? crtc->mode.hdisplay : 0;
+               master_priv->sarea_priv->planeA_h = enabled ? crtc->mode.vdisplay : 0;
+               break;
+       case 1:
+               master_priv->sarea_priv->planeB_w = enabled ? crtc->mode.hdisplay : 0;
+               master_priv->sarea_priv->planeB_h = enabled ? crtc->mode.vdisplay : 0;
+               break;
+       default:
+               DRM_ERROR("Can't update pipe %d in SAREA\n", pipe);
+               break;
+       }
+}
+
+static bool intel_crtc_lock(struct drm_crtc *crtc)
+{
+   /* Sync the engine before mode switch */
+//   i830WaitSync(crtc->scrn);
+
+#if 0 // TODO def XF86DRI
+    return I830DRILock(crtc->scrn);
+#else
+    return FALSE;
+#endif
+}
+
+static void intel_crtc_unlock (struct drm_crtc *crtc)
+{
+#if 0 // TODO def XF86DRI
+    I830DRIUnlock (crtc->scrn);
+#endif
+}
+
+static void intel_crtc_prepare (struct drm_crtc *crtc)
+{
+       crtc->funcs->dpms(crtc, DPMSModeOff);
+}
+
+static void intel_crtc_commit (struct drm_crtc *crtc)
+{
+       crtc->funcs->dpms(crtc, DPMSModeOn);
+}
+
+void intel_output_prepare (struct drm_output *output)
+{
+       /* lvds has its own version of prepare see intel_lvds_prepare */
+       output->funcs->dpms(output, DPMSModeOff);
+}
+
+void intel_output_commit (struct drm_output *output)
+{
+       /* lvds has its own version of commit see intel_lvds_commit */
+       output->funcs->dpms(output, DPMSModeOn);
+}
+
+static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
+                                 struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+
+/** Returns the core display clock speed for i830 - i945 */
+static int intel_get_core_clock_speed(struct drm_device *dev)
+{
+
+       /* Core clock values taken from the published datasheets.
+        * The 830 may go up to 166 Mhz, which we should check.
+        */
+       if (IS_I945G(dev))
+               return 400000;
+       else if (IS_I915G(dev))
+               return 333000;
+       else if (IS_I945GM(dev) || IS_845G(dev))
+               return 200000;
+       else if (IS_I915GM(dev)) {
+               u16 gcfgc = 0;
+
+               pci_read_config_word(dev->pdev, I915_GCFGC, &gcfgc);
+               
+               if (gcfgc & I915_LOW_FREQUENCY_ENABLE)
+                       return 133000;
+               else {
+                       switch (gcfgc & I915_DISPLAY_CLOCK_MASK) {
+                       case I915_DISPLAY_CLOCK_333_MHZ:
+                               return 333000;
+                       default:
+                       case I915_DISPLAY_CLOCK_190_200_MHZ:
+                               return 190000;
+                       }
+               }
+       } else if (IS_I865G(dev))
+               return 266000;
+       else if (IS_I855(dev)) {
+#if 0
+               PCITAG bridge = pciTag(0, 0, 0); /* This is always the host bridge */
+               u16 hpllcc = pciReadWord(bridge, I855_HPLLCC);
+               
+#endif
+               u16 hpllcc = 0;
+               /* Assume that the hardware is in the high speed state.  This
+                * should be the default.
+                */
+               switch (hpllcc & I855_CLOCK_CONTROL_MASK) {
+               case I855_CLOCK_133_200:
+               case I855_CLOCK_100_200:
+                       return 200000;
+               case I855_CLOCK_166_250:
+                       return 250000;
+               case I855_CLOCK_100_133:
+                       return 133000;
+               }
+       } else /* 852, 830 */
+               return 133000;
+       
+       return 0; /* Silence gcc warning */
+}
+
+
+/**
+ * Return the pipe currently connected to the panel fitter,
+ * or -1 if the panel fitter is not present or not in use
+ */
+static int intel_panel_fitter_pipe (struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32  pfit_control;
+    
+       /* i830 doesn't have a panel fitter */
+       if (IS_I830(dev))
+               return -1;
+    
+       pfit_control = I915_READ(PFIT_CONTROL);
+    
+       /* See if the panel fitter is in use */
+       if ((pfit_control & PFIT_ENABLE) == 0)
+               return -1;
+       
+       /* 965 can place panel fitter on either pipe */
+       if (IS_I965G(dev))
+               return (pfit_control >> 29) & 0x3;
+       
+       /* older chips can only use pipe 1 */
+       return 1;
+}
+
+static void intel_crtc_mode_set(struct drm_crtc *crtc,
+                               struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode,
+                               int x, int y)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = crtc->driver_private;
+       int pipe = intel_crtc->pipe;
+       int fp_reg = (pipe == 0) ? FPA0 : FPB0;
+       int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
+       int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
+       int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
+       int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+       int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
+       int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
+       int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
+       int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
+       int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
+       int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
+       int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;
+       int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
+       int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
+       int refclk;
+       intel_clock_t clock;
+       u32 dpll = 0, fp = 0, dspcntr, pipeconf;
+       bool ok, is_sdvo = false, is_dvo = false;
+       bool is_crt = false, is_lvds = false, is_tv = false;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct drm_output *output;
+
+       list_for_each_entry(output, &mode_config->output_list, head) {
+               struct intel_output *intel_output = output->driver_private;
+
+               if (output->crtc != crtc)
+                       continue;
+
+               switch (intel_output->type) {
+               case INTEL_OUTPUT_LVDS:
+                       is_lvds = TRUE;
+                       break;
+               case INTEL_OUTPUT_SDVO:
+                       is_sdvo = TRUE;
+                       break;
+               case INTEL_OUTPUT_DVO:
+                       is_dvo = TRUE;
+                       break;
+               case INTEL_OUTPUT_TVOUT:
+                       is_tv = TRUE;
+                       break;
+               case INTEL_OUTPUT_ANALOG:
+                       is_crt = TRUE;
+                       break;
+               }
+       }
+       
+       if (IS_I9XX(dev)) {
+               refclk = 96000;
+       } else {
+               refclk = 48000;
+       }
+
+       ok = intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, &clock);
+       if (!ok) {
+               DRM_ERROR("Couldn't find PLL settings for mode!\n");
+               return;
+       }
+
+       fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
+       
+       dpll = DPLL_VGA_MODE_DIS;
+       if (IS_I9XX(dev)) {
+               if (is_lvds)
+                       dpll |= DPLLB_MODE_LVDS;
+               else
+                       dpll |= DPLLB_MODE_DAC_SERIAL;
+               if (is_sdvo) {
+                       dpll |= DPLL_DVO_HIGH_SPEED;
+                       if (IS_I945G(dev) || IS_I945GM(dev)) {
+                               int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
+                               dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
+                       }
+               }
+               
+               /* compute bitmask from p1 value */
+               dpll |= (1 << (clock.p1 - 1)) << 16;
+               switch (clock.p2) {
+               case 5:
+                       dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
+                       break;
+               case 7:
+                       dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
+                       break;
+               case 10:
+                       dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
+                       break;
+               case 14:
+                       dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
+                       break;
+               }
+               if (IS_I965G(dev))
+                       dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
+       } else {
+               if (is_lvds) {
+                       dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+               } else {
+                       if (clock.p1 == 2)
+                               dpll |= PLL_P1_DIVIDE_BY_TWO;
+                       else
+                               dpll |= (clock.p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+                       if (clock.p2 == 4)
+                               dpll |= PLL_P2_DIVIDE_BY_4;
+               }
+       }
+       
+       if (is_tv) {
+               /* XXX: just matching BIOS for now */
+/*     dpll |= PLL_REF_INPUT_TVCLKINBC; */
+               dpll |= 3;
+       }
+#if 0
+       else if (is_lvds)
+               dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
+#endif
+       else
+               dpll |= PLL_REF_INPUT_DREFCLK;
+       
+       /* setup pipeconf */
+       pipeconf = I915_READ(pipeconf_reg);
+
+       /* Set up the display plane register */
+       dspcntr = DISPPLANE_GAMMA_ENABLE;
+
+       if (pipe == 0)
+               dspcntr |= DISPPLANE_SEL_PIPE_A;
+       else
+               dspcntr |= DISPPLANE_SEL_PIPE_B;
+       
+       if (pipe == 0 && !IS_I965G(dev)) {
+               /* Enable pixel doubling when the dot clock is > 90% of the (display)
+                * core speed.
+                *
+                * XXX: No double-wide on 915GM pipe B. Is that the only reason for the
+                * pipe == 0 check?
+                */
+               if (mode->clock > intel_get_core_clock_speed(dev) * 9 / 10)
+                       pipeconf |= PIPEACONF_DOUBLE_WIDE;
+               else
+                       pipeconf &= ~PIPEACONF_DOUBLE_WIDE;
+       }
+
+       dspcntr |= DISPLAY_PLANE_ENABLE;
+       pipeconf |= PIPEACONF_ENABLE;
+       dpll |= DPLL_VCO_ENABLE;
+
+       
+       /* Disable the panel fitter if it was on our pipe */
+       if (intel_panel_fitter_pipe(dev) == pipe)
+               I915_WRITE(PFIT_CONTROL, 0);
+
+       DRM_DEBUG("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
+       drm_mode_debug_printmodeline(dev, mode);
+       
+#if 0
+       if (!xf86ModesEqual(mode, adjusted_mode)) {
+               xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+                          "Adjusted mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
+               xf86PrintModeline(pScrn->scrnIndex, mode);
+       }
+       i830PrintPll("chosen", &clock);
+#endif
+
+       if (dpll & DPLL_VCO_ENABLE) {
+               I915_WRITE(fp_reg, fp);
+               I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
+               I915_READ(dpll_reg);
+               udelay(150);
+       }
+       
+       /* The LVDS pin pair needs to be on before the DPLLs are enabled.
+        * This is an exception to the general rule that mode_set doesn't turn
+        * things on.
+        */
+       if (is_lvds) {
+               u32 lvds = I915_READ(LVDS);
+               
+               lvds |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT;
+               /* Set the B0-B3 data pairs corresponding to whether we're going to
+                * set the DPLLs for dual-channel mode or not.
+                */
+               if (clock.p2 == 7)
+                       lvds |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
+               else
+                       lvds &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
+               
+               /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
+                * appropriately here, but we need to look more thoroughly into how
+                * panels behave in the two modes.
+                */
+               
+               I915_WRITE(LVDS, lvds);
+               I915_READ(LVDS);
+       }
+       
+       I915_WRITE(fp_reg, fp);
+       I915_WRITE(dpll_reg, dpll);
+       I915_READ(dpll_reg);
+       /* Wait for the clocks to stabilize. */
+       udelay(150);
+       
+       if (IS_I965G(dev)) {
+               int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
+               I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
+                          ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
+       } else {
+               /* write it again -- the BIOS does, after all */
+               I915_WRITE(dpll_reg, dpll);
+       }
+       I915_READ(dpll_reg);
+       /* Wait for the clocks to stabilize. */
+       udelay(150);
+       
+       I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
+                  ((adjusted_mode->crtc_htotal - 1) << 16));
+       I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
+                  ((adjusted_mode->crtc_hblank_end - 1) << 16));
+       I915_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) |
+                  ((adjusted_mode->crtc_hsync_end - 1) << 16));
+       I915_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) |
+                  ((adjusted_mode->crtc_vtotal - 1) << 16));
+       I915_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) |
+                  ((adjusted_mode->crtc_vblank_end - 1) << 16));
+       I915_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
+                  ((adjusted_mode->crtc_vsync_end - 1) << 16));
+       /* pipesrc and dspsize control the size that is scaled from, which should
+        * always be the user's requested size.
+        */
+       I915_WRITE(dspsize_reg, ((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
+       I915_WRITE(dsppos_reg, 0);
+       I915_WRITE(pipesrc_reg, ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
+       I915_WRITE(pipeconf_reg, pipeconf);
+       I915_READ(pipeconf_reg);
+       
+       intel_wait_for_vblank(dev);
+       
+       I915_WRITE(dspcntr_reg, dspcntr);
+       
+       /* Flush the plane changes */
+       intel_pipe_set_base(crtc, x, y);
+       
+       intel_set_vblank(dev);
+
+       intel_wait_for_vblank(dev);    
+}
+
+/** Loads the palette/gamma unit for the CRTC with the prepared values */
+void intel_crtc_load_lut(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = crtc->driver_private;
+       int palreg = (intel_crtc->pipe == 0) ? PALETTE_A : PALETTE_B;
+       int i;
+
+       /* The clocks have to be on to load the palette. */
+       if (!crtc->enabled)
+               return;
+
+       for (i = 0; i < 256; i++) {
+               I915_WRITE(palreg + 4 * i,
+                          (intel_crtc->lut_r[i] << 16) |
+                          (intel_crtc->lut_g[i] << 8) |
+                          intel_crtc->lut_b[i]);
+       }
+}
+
+#define CURSOR_A_CONTROL        0x70080
+#define CURSOR_A_BASE           0x70084
+#define CURSOR_A_POSITION       0x70088
+
+#define CURSOR_B_CONTROL        0x700C0
+#define CURSOR_B_BASE           0x700C4
+#define CURSOR_B_POSITION       0x700C8
+
+#define CURSOR_MODE_DISABLE     0x00
+#define CURSOR_MODE_64_32B_AX   0x07
+#define CURSOR_MODE_64_ARGB_AX  ((1 << 5) | CURSOR_MODE_64_32B_AX)
+#define MCURSOR_GAMMA_ENABLE    (1 << 26)
+
+#define CURSOR_POS_MASK         0x007FF
+#define CURSOR_POS_SIGN         0x8000
+#define CURSOR_X_SHIFT          0
+#define CURSOR_Y_SHIFT          16
+
+static int intel_crtc_cursor_set(struct drm_crtc *crtc,
+                                struct drm_buffer_object *bo,
+                                uint32_t width, uint32_t height)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = crtc->driver_private;
+       int pipe = intel_crtc->pipe;
+       uint32_t control = (pipe == 0) ? CURSOR_A_CONTROL : CURSOR_B_CONTROL;
+       uint32_t base = (pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE;
+       uint32_t temp;
+       size_t adder;
+
+       DRM_DEBUG("\n");
+
+       /* if we want to turn of the cursor ignore width and height */
+       if (!bo) {
+               DRM_DEBUG("cursor off\n");
+               /* turn of the cursor */
+               temp = 0;
+               temp |= CURSOR_MODE_DISABLE;
+
+               I915_WRITE(control, temp);
+               I915_WRITE(base, 0);
+               return 0;
+       }
+
+       /* Currently we only support 64x64 cursors */
+       if (width != 64 || height != 64) {
+               DRM_ERROR("we currently only support 64x64 cursors\n");
+               return -EINVAL;
+       }
+
+       if ((bo->mem.flags & DRM_BO_MASK_MEM) != DRM_BO_FLAG_MEM_VRAM) {
+               DRM_ERROR("buffer needs to be in VRAM\n");
+               return -ENOMEM;
+       }
+
+       if (bo->mem.size < width * height * 4) {
+               DRM_ERROR("buffer is to small\n");
+               return -ENOMEM;
+       }
+
+       adder = dev_priv->stolen_base + bo->offset;
+       intel_crtc->cursor_adder = adder;
+       temp = 0;
+       /* set the pipe for the cursor */
+       temp |= (pipe << 28);
+       temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
+
+       DRM_DEBUG("cusror base %x\n", adder);
+
+       I915_WRITE(control, temp);
+       I915_WRITE(base, adder);
+
+       return 0;
+}
+
+static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = crtc->driver_private;
+       int pipe = intel_crtc->pipe;
+       uint32_t temp = 0;
+       uint32_t adder;
+
+       if (x < 0) {
+               temp |= (CURSOR_POS_SIGN << CURSOR_X_SHIFT);
+               x = -x;
+       }
+       if (y < 0) {
+               temp |= (CURSOR_POS_SIGN << CURSOR_Y_SHIFT);
+               y = -y;
+       }
+
+       temp |= ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT);
+       temp |= ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT);
+
+       adder = intel_crtc->cursor_adder;
+       I915_WRITE((pipe == 0) ? CURSOR_A_POSITION : CURSOR_B_POSITION, temp);
+       I915_WRITE((pipe == 0) ? CURSOR_A_BASE : CURSOR_B_BASE, adder);
+
+       return 0;
+}
+
+/** Sets the color ramps on behalf of RandR */
+static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+                                u16 blue, int regno)
+{
+       struct intel_crtc *intel_crtc = crtc->driver_private;
+       
+       intel_crtc->lut_r[regno] = red >> 8;
+       intel_crtc->lut_g[regno] = green >> 8;
+       intel_crtc->lut_b[regno] = blue >> 8;
+}
+
+/* Returns the clock of the currently programmed mode of the given pipe. */
+static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = crtc->driver_private;
+       int pipe = intel_crtc->pipe;
+       u32 dpll = I915_READ((pipe == 0) ? DPLL_A : DPLL_B);
+       u32 fp;
+       intel_clock_t clock;
+
+       if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
+               fp = I915_READ((pipe == 0) ? FPA0 : FPB0);
+       else
+               fp = I915_READ((pipe == 0) ? FPA1 : FPB1);
+
+       clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT;
+       clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT;
+       clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT;
+       if (IS_I9XX(dev)) {
+               clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >>
+                              DPLL_FPA01_P1_POST_DIV_SHIFT);
+
+               switch (dpll & DPLL_MODE_MASK) {
+               case DPLLB_MODE_DAC_SERIAL:
+                       clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ?
+                               5 : 10;
+                       break;
+               case DPLLB_MODE_LVDS:
+                       clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ?
+                               7 : 14;
+                       break;
+               default:
+                       DRM_DEBUG("Unknown DPLL mode %08x in programmed "
+                                 "mode\n", (int)(dpll & DPLL_MODE_MASK));
+                       return 0;
+               }
+
+               /* XXX: Handle the 100Mhz refclk */
+               i9xx_clock(96000, &clock);
+       } else {
+               bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN);
+
+               if (is_lvds) {
+                       clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >>
+                                      DPLL_FPA01_P1_POST_DIV_SHIFT);
+                       clock.p2 = 14;
+
+                       if ((dpll & PLL_REF_INPUT_MASK) ==
+                           PLLB_REF_INPUT_SPREADSPECTRUMIN) {
+                               /* XXX: might not be 66MHz */
+                               i8xx_clock(66000, &clock);
+                       } else
+                               i8xx_clock(48000, &clock);              
+               } else {
+                       if (dpll & PLL_P1_DIVIDE_BY_TWO)
+                               clock.p1 = 2;
+                       else {
+                               clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >>
+                                           DPLL_FPA01_P1_POST_DIV_SHIFT) + 2;
+                       }
+                       if (dpll & PLL_P2_DIVIDE_BY_4)
+                               clock.p2 = 4;
+                       else
+                               clock.p2 = 2;
+
+                       i8xx_clock(48000, &clock);
+               }
+       }
+
+       /* XXX: It would be nice to validate the clocks, but we can't reuse
+        * i830PllIsValid() because it relies on the xf86_config output
+        * configuration being accurate, which it isn't necessarily.
+        */
+
+       return clock.dot;
+}
+
+/** Returns the currently programmed mode of the given pipe. */
+struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
+                                            struct drm_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = crtc->driver_private;
+       int pipe = intel_crtc->pipe;
+       struct drm_display_mode *mode;
+       int htot = I915_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B);
+       int hsync = I915_READ((pipe == 0) ? HSYNC_A : HSYNC_B);
+       int vtot = I915_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B);
+       int vsync = I915_READ((pipe == 0) ? VSYNC_A : VSYNC_B);
+
+       mode = kzalloc(sizeof(*mode), GFP_KERNEL);
+       if (!mode)
+               return NULL;
+
+       mode->clock = intel_crtc_clock_get(dev, crtc);
+       mode->hdisplay = (htot & 0xffff) + 1;
+       mode->htotal = ((htot & 0xffff0000) >> 16) + 1;
+       mode->hsync_start = (hsync & 0xffff) + 1;
+       mode->hsync_end = ((hsync & 0xffff0000) >> 16) + 1;
+       mode->vdisplay = (vtot & 0xffff) + 1;
+       mode->vtotal = ((vtot & 0xffff0000) >> 16) + 1;
+       mode->vsync_start = (vsync & 0xffff) + 1;
+       mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1;
+
+       drm_mode_set_name(mode);
+       drm_mode_set_crtcinfo(mode, 0);
+
+       return mode;
+}
+
+static const struct drm_crtc_funcs intel_crtc_funcs = {
+       .dpms = intel_crtc_dpms,
+       .lock = intel_crtc_lock,
+       .unlock = intel_crtc_unlock,
+       .mode_fixup = intel_crtc_mode_fixup,
+       .mode_set = intel_crtc_mode_set,
+       .mode_set_base = intel_pipe_set_base,
+       .cursor_set = intel_crtc_cursor_set,
+       .cursor_move = intel_crtc_cursor_move,
+       .gamma_set = intel_crtc_gamma_set,
+       .prepare = intel_crtc_prepare,
+       .commit = intel_crtc_commit,
+};
+
+
+void intel_crtc_init(struct drm_device *dev, int pipe)
+{
+       struct drm_crtc *crtc;
+       struct intel_crtc *intel_crtc;
+       int i;
+
+       crtc = drm_crtc_create(dev, &intel_crtc_funcs);
+       if (crtc == NULL)
+               return;
+
+       intel_crtc = kzalloc(sizeof(struct intel_crtc), GFP_KERNEL);
+       if (intel_crtc == NULL) {
+               kfree(crtc);
+               return;
+       }
+
+       intel_crtc->pipe = pipe;
+       for (i = 0; i < 256; i++) {
+               intel_crtc->lut_r[i] = i;
+               intel_crtc->lut_g[i] = i;
+               intel_crtc->lut_b[i] = i;
+       }
+
+       intel_crtc->cursor_adder = 0;
+
+       crtc->driver_private = intel_crtc;
+}
+
+struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
+{
+       struct drm_crtc *crtc = NULL;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct intel_crtc *intel_crtc = crtc->driver_private;
+               if (intel_crtc->pipe == pipe)
+                       break;
+       }
+       return crtc;
+}
+
+int intel_output_clones(struct drm_device *dev, int type_mask)
+{
+       int index_mask = 0;
+       struct drm_output *output;
+       int entry = 0;
+
+        list_for_each_entry(output, &dev->mode_config.output_list, head) {
+               struct intel_output *intel_output = output->driver_private;
+               if (type_mask & (1 << intel_output->type))
+                       index_mask |= (1 << entry);
+               entry++;
+       }
+       return index_mask;
+}
+
+
+static void intel_setup_outputs(struct drm_device *dev)
+{
+       struct drm_output *output;
+
+       intel_crt_init(dev);
+
+       /* Set up integrated LVDS */
+       if (IS_MOBILE(dev) && !IS_I830(dev))
+               intel_lvds_init(dev);
+
+       if (IS_I9XX(dev)) {
+               intel_sdvo_init(dev, SDVOB);
+               intel_sdvo_init(dev, SDVOC);
+       }
+
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+               struct intel_output *intel_output = output->driver_private;
+               int crtc_mask = 0, clone_mask = 0;
+               
+               /* valid crtcs */
+               switch(intel_output->type) {
+               case INTEL_OUTPUT_DVO:
+               case INTEL_OUTPUT_SDVO:
+                       crtc_mask = ((1 << 0)|
+                                    (1 << 1));
+                       clone_mask = ((1 << INTEL_OUTPUT_ANALOG) |
+                                     (1 << INTEL_OUTPUT_DVO) |
+                                     (1 << INTEL_OUTPUT_SDVO));
+                       break;
+               case INTEL_OUTPUT_ANALOG:
+                       crtc_mask = ((1 << 0)|
+                                    (1 << 1));
+                       clone_mask = ((1 << INTEL_OUTPUT_ANALOG) |
+                                     (1 << INTEL_OUTPUT_DVO) |
+                                     (1 << INTEL_OUTPUT_SDVO));
+                       break;
+               case INTEL_OUTPUT_LVDS:
+                       crtc_mask = (1 << 1);
+                       clone_mask = (1 << INTEL_OUTPUT_LVDS);
+                       break;
+               case INTEL_OUTPUT_TVOUT:
+                       crtc_mask = ((1 << 0) |
+                                    (1 << 1));
+                       clone_mask = (1 << INTEL_OUTPUT_TVOUT);
+                       break;
+               }
+               output->possible_crtcs = crtc_mask;
+               output->possible_clones = intel_output_clones(dev, clone_mask);
+       }
+}
+
+void intel_modeset_init(struct drm_device *dev)
+{
+       int num_pipe;
+       int i;
+
+       drm_mode_config_init(dev);
+
+       dev->mode_config.min_width = 0;
+       dev->mode_config.min_height = 0;
+
+       dev->mode_config.max_width = 4096;
+       dev->mode_config.max_height = 4096;
+
+       /* set memory base */
+       if (IS_I9XX(dev))
+               dev->mode_config.fb_base = pci_resource_start(dev->pdev, 2);
+       else
+               dev->mode_config.fb_base = pci_resource_start(dev->pdev, 0);
+
+       if (IS_MOBILE(dev) || IS_I9XX(dev))
+               num_pipe = 2;
+       else
+               num_pipe = 1;
+       DRM_DEBUG("%d display pipe%s available.\n",
+                 num_pipe, num_pipe > 1 ? "s" : "");
+
+       for (i = 0; i < num_pipe; i++) {
+               intel_crtc_init(dev, i);
+       }
+
+       intel_setup_outputs(dev);
+
+       //drm_initial_config(dev, false);
+}
+
+void intel_modeset_cleanup(struct drm_device *dev)
+{
+       drm_mode_config_cleanup(dev);
+}
diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h
new file mode 100644 (file)
index 0000000..72ba01d
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
+ * Copyright (c) 2007 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ */
+#ifndef __INTEL_DRV_H__
+#define __INTEL_DRV_H__
+
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+#include "drm_crtc.h"
+
+/*
+ * Display related stuff
+ */
+
+/* store information about an Ixxx DVO */
+/* The i830->i865 use multiple DVOs with multiple i2cs */
+/* the i915, i945 have a single sDVO i2c bus - which is different */
+#define MAX_OUTPUTS 6
+
+#define INTEL_I2C_BUS_DVO 1
+#define INTEL_I2C_BUS_SDVO 2
+
+/* these are outputs from the chip - integrated only 
+   external chips are via DVO or SDVO output */
+#define INTEL_OUTPUT_UNUSED 0
+#define INTEL_OUTPUT_ANALOG 1
+#define INTEL_OUTPUT_DVO 2
+#define INTEL_OUTPUT_SDVO 3
+#define INTEL_OUTPUT_LVDS 4
+#define INTEL_OUTPUT_TVOUT 5
+
+#define INTEL_DVO_CHIP_NONE 0
+#define INTEL_DVO_CHIP_LVDS 1
+#define INTEL_DVO_CHIP_TMDS 2
+#define INTEL_DVO_CHIP_TVOUT 4
+
+struct intel_i2c_chan {
+       struct drm_device *drm_dev; /* for getting at dev. private (mmio etc.) */
+       u32 reg; /* GPIO reg */
+       struct i2c_adapter adapter;
+       struct i2c_algo_bit_data algo;
+        u8 slave_addr;
+};
+
+struct intel_output {
+       int type;
+       struct intel_i2c_chan *i2c_bus; /* for control functions */
+       struct intel_i2c_chan *ddc_bus; /* for DDC only stuff */
+       bool load_detect_temp;
+       void *dev_priv;
+};
+
+struct intel_crtc {
+       int pipe;
+       int plane;
+       uint32_t cursor_adder;
+       u8 lut_r[256], lut_g[256], lut_b[256];
+};
+
+struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
+                                       const char *name);
+void intel_i2c_destroy(struct intel_i2c_chan *chan);
+int intel_ddc_get_modes(struct drm_output *output);
+extern bool intel_ddc_probe(struct drm_output *output);
+
+extern void intel_crt_init(struct drm_device *dev);
+extern void intel_sdvo_init(struct drm_device *dev, int output_device);
+extern void intel_lvds_init(struct drm_device *dev);
+
+extern void intel_crtc_load_lut(struct drm_crtc *crtc);
+extern void intel_output_prepare (struct drm_output *output);
+extern void intel_output_commit (struct drm_output *output);
+extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
+                                                   struct drm_crtc *crtc);
+extern void intel_wait_for_vblank(struct drm_device *dev);
+extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe);
+
+extern struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB);
+extern int intel_sdvo_supports_hotplug(struct drm_output *output);
+extern void intel_sdvo_set_hotplug(struct drm_output *output, int enable);
+
+extern int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc);
+extern int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc);
+extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc);
+
+#endif /* __INTEL_DRV_H__ */
diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c
new file mode 100644 (file)
index 0000000..e33494c
--- /dev/null
@@ -0,0 +1,752 @@
+/*
+ * Copyright Â© 2007 David Airlie
+ *
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ *     David Airlie
+ */
+    /*
+     *  Modularization
+     */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+struct intelfb_par {
+       struct drm_device *dev;
+       struct drm_crtc *crtc;
+        struct drm_display_mode *fb_mode;
+       struct drm_framebuffer *fb;
+};
+/*
+static int
+var_to_refresh(const struct fb_var_screeninfo *var)
+{
+       int xtot = var->xres + var->left_margin + var->right_margin +
+                  var->hsync_len;
+       int ytot = var->yres + var->upper_margin + var->lower_margin +
+                  var->vsync_len;
+
+       return (1000000000 / var->pixclock * 1000 + 500) / xtot / ytot;
+}*/
+
+static int intelfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                          unsigned blue, unsigned transp,
+                          struct fb_info *info)
+{
+       struct intelfb_par *par = info->par;
+       struct drm_framebuffer *fb = par->fb;
+       struct drm_crtc *crtc = par->crtc;
+
+       if (regno > 255)
+               return 1;
+
+       if (fb->depth == 8) {
+               if (crtc->funcs->gamma_set)
+                       crtc->funcs->gamma_set(crtc, red, green, blue, regno);
+               return 0;
+       }
+
+       if (regno < 16) {
+               switch (fb->depth) {
+               case 15:
+                       fb->pseudo_palette[regno] = ((red & 0xf800) >>  1) |
+                               ((green & 0xf800) >>  6) |
+                               ((blue & 0xf800) >> 11);
+                       break;
+               case 16:
+                       fb->pseudo_palette[regno] = (red & 0xf800) |
+                               ((green & 0xfc00) >>  5) |
+                               ((blue  & 0xf800) >> 11);
+                       break;
+               case 24:
+               case 32:
+                       fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
+                               (green & 0xff00) |
+                               ((blue  & 0xff00) >> 8);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int intelfb_check_var(struct fb_var_screeninfo *var,
+                            struct fb_info *info)
+{
+        struct intelfb_par *par = info->par;
+        /*struct drm_device *dev = par->dev;*/
+       struct drm_framebuffer *fb = par->fb;
+        /*struct drm_output *output;*/
+        int depth/*, found = 0*/;
+
+        if (!var->pixclock)
+                return -EINVAL;
+
+        /* Need to resize the fb object !!! */
+        if (var->xres > fb->width || var->yres > fb->height) {
+                DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height);
+                DRM_ERROR("Need resizing code.\n");
+                return -EINVAL;
+        }
+
+        switch (var->bits_per_pixel) {
+        case 16:
+                depth = (var->green.length == 6) ? 16 : 15;
+                break;
+        case 32:
+                depth = (var->transp.length > 0) ? 32 : 24;
+                break;
+        default:
+                depth = var->bits_per_pixel;
+                break;
+        }
+                
+        switch (depth) {
+        case 8:
+                var->red.offset = 0;
+                var->green.offset = 0;
+                var->blue.offset = 0;
+                var->red.length = 8;
+                var->green.length = 8;
+                var->blue.length = 8;
+                var->transp.length = 0;
+                var->transp.offset = 0;
+                break;
+        case 15:
+                var->red.offset = 10;
+                var->green.offset = 5;
+                var->blue.offset = 0;
+                var->red.length = 5;
+                var->green.length = 5;
+                var->blue.length = 5;
+                var->transp.length = 1;
+                var->transp.offset = 15;
+                break;
+        case 16:
+                var->red.offset = 11;
+                var->green.offset = 6;
+                var->blue.offset = 0;
+                var->red.length = 5;
+                var->green.length = 6;
+                var->blue.length = 5;
+                var->transp.length = 0;
+                var->transp.offset = 0;
+                break;
+        case 24:
+                var->red.offset = 16;
+                var->green.offset = 8;
+                var->blue.offset = 0;
+                var->red.length = 8;
+                var->green.length = 8;
+                var->blue.length = 8;
+                var->transp.length = 0;
+                var->transp.offset = 0;
+                break;
+        case 32:
+                var->red.offset = 16;
+                var->green.offset = 8;
+                var->blue.offset = 0;
+                var->red.length = 8;
+                var->green.length = 8;
+                var->blue.length = 8;
+                var->transp.length = 8;
+                var->transp.offset = 24;
+                break;
+        default:
+                return -EINVAL; 
+        }
+
+#if 0
+        /* Here we walk the output mode list and look for modes. If we haven't
+         * got it, then bail. Not very nice, so this is disabled.
+         * In the set_par code, we create our mode based on the incoming
+         * parameters. Nicer, but may not be desired by some.
+         */
+        list_for_each_entry(output, &dev->mode_config.output_list, head) {
+                if (output->crtc == par->crtc)
+                        break;
+        }
+    
+        list_for_each_entry(drm_mode, &output->modes, head) {
+                if (drm_mode->hdisplay == var->xres &&
+                    drm_mode->vdisplay == var->yres &&
+                    (((PICOS2KHZ(var->pixclock))/1000) >= ((drm_mode->clock/1000)-1)) &&
+                    (((PICOS2KHZ(var->pixclock))/1000) <= ((drm_mode->clock/1000)+1))) {
+                       found = 1;
+                       break;
+               }
+       }
+        if (!found)
+                return -EINVAL;
+#endif
+
+       return 0;
+}
+
+/* this will let fbcon do the mode init */
+/* FIXME: take mode config lock? */
+static int intelfb_set_par(struct fb_info *info)
+{
+       struct intelfb_par *par = info->par;
+       struct drm_framebuffer *fb = par->fb;
+       struct drm_device *dev = par->dev;
+        struct drm_display_mode *drm_mode, *search_mode;
+        struct drm_output *output = NULL;
+        struct fb_var_screeninfo *var = &info->var;
+       int found = 0;
+
+       DRM_DEBUG("\n");
+
+        switch (var->bits_per_pixel) {
+        case 16:
+                fb->depth = (var->green.length == 6) ? 16 : 15;
+                break;
+        case 32:
+                fb->depth = (var->transp.length > 0) ? 32 : 24;
+                break;
+        default:
+                fb->depth = var->bits_per_pixel;
+                break;
+        }
+
+        fb->bits_per_pixel = var->bits_per_pixel;
+
+        info->fix.line_length = fb->pitch;
+        info->fix.smem_len = info->fix.line_length * fb->height;
+        info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+
+        info->screen_size = info->fix.smem_len; /* ??? */
+
+       /* create a drm mode */
+        drm_mode = drm_mode_create(dev);
+        drm_mode->hdisplay = var->xres;
+        drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin;
+        drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len;
+        drm_mode->htotal = drm_mode->hsync_end + var->left_margin;
+        drm_mode->vdisplay = var->yres;
+        drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin;
+        drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len;
+        drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin;
+        drm_mode->clock = PICOS2KHZ(var->pixclock);
+        drm_mode->vrefresh = drm_mode_vrefresh(drm_mode);
+       drm_mode->flags = 0;
+       drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC;
+       drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC;
+
+        drm_mode_set_name(drm_mode);
+       drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V);
+
+       found = 0;
+        list_for_each_entry(output, &dev->mode_config.output_list, head) {
+                if (output->crtc == par->crtc){
+                       found = 1;
+                        break;
+               }
+        }
+
+       /* no output bound, bail */
+       if (!found)
+               return -EINVAL;
+
+       found = 0;
+       drm_mode_debug_printmodeline(dev, drm_mode);    
+        list_for_each_entry(search_mode, &output->modes, head) {
+               drm_mode_debug_printmodeline(dev, search_mode);
+               if (drm_mode_equal(drm_mode, search_mode)) {
+                       drm_mode_destroy(dev, drm_mode);
+                       drm_mode = search_mode;
+                       found = 1;
+                       break;
+               }
+       }
+       
+       /* If we didn't find a matching mode that exists on our output,
+        * create a new attachment for the incoming user specified mode
+        */
+       if (!found) {
+               if (par->fb_mode) {
+                       /* this also destroys the mode */
+                       drm_mode_detachmode_crtc(dev, par->fb_mode);
+               }
+       
+               par->fb_mode = drm_mode;
+               drm_mode_debug_printmodeline(dev, drm_mode);
+               /* attach mode */
+               drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode);
+       }
+
+       /* re-attach fb */
+       if (!par->crtc->fb)
+               par->crtc->fb = par->fb;
+
+       if (!drm_crtc_set_mode(par->crtc, drm_mode, var->xoffset, var->yoffset))
+               return -EINVAL;
+
+       return 0;
+}
+
+#if 0
+static void intelfb_copyarea(struct fb_info *info,
+                            const struct fb_copyarea *region)
+{
+        struct intelfb_par *par = info->par;
+       struct drm_device *dev = par->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 src_x1, src_y1, dst_x1, dst_y1, dst_x2, dst_y2, offset;
+       u32 cmd, rop_depth_pitch, src_pitch;
+       RING_LOCALS;
+
+       cmd = XY_SRC_COPY_BLT_CMD;
+       src_x1 = region->sx;
+       src_y1 = region->sy;
+       dst_x1 = region->dx;
+       dst_y1 = region->dy;
+       dst_x2 = region->dx + region->width;
+       dst_y2 = region->dy + region->height;
+       offset = par->fb->offset;
+       rop_depth_pitch = BLT_ROP_GXCOPY | par->fb->pitch;
+       src_pitch = par->fb->pitch;
+
+       switch (par->fb->bits_per_pixel) {
+       case 16:
+               rop_depth_pitch |= BLT_DEPTH_16_565;
+               break;
+       case 32:
+               rop_depth_pitch |= BLT_DEPTH_32;
+               cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
+               break;
+       }
+
+       BEGIN_LP_RING(8);
+       OUT_RING(cmd);
+       OUT_RING(rop_depth_pitch);
+       OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff));
+       OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff));
+       OUT_RING(offset);
+       OUT_RING((src_y1 << 16) | (src_x1 & 0xffff));
+       OUT_RING(src_pitch);
+       OUT_RING(offset);
+       ADVANCE_LP_RING();
+}
+
+#define ROUND_UP_TO(x, y)      (((x) + (y) - 1) / (y) * (y))
+#define ROUND_DOWN_TO(x, y)    ((x) / (y) * (y))
+
+void intelfb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+        struct intelfb_par *par = info->par;
+       struct drm_device *dev = par->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 cmd, rop_pitch_depth, tmp;
+       int nbytes, ndwords, pad;
+       u32 dst_x1, dst_y1, dst_x2, dst_y2, offset, bg, fg;
+       int dat, ix, iy, iw;
+       int i, j;
+       RING_LOCALS;
+
+       /* size in bytes of a padded scanline */
+       nbytes = ROUND_UP_TO(image->width, 16) / 8;
+
+       /* Total bytes of padded scanline data to write out. */
+       nbytes *= image->height;
+
+       /*
+        * Check if the glyph data exceeds the immediate mode limit.
+        * It would take a large font (1K pixels) to hit this limit.
+        */
+       if (nbytes > 128 || image->depth != 1)
+               return cfb_imageblit(info, image);
+
+       /* Src data is packaged a dword (32-bit) at a time. */
+       ndwords = ROUND_UP_TO(nbytes, 4) / 4;
+
+       /*
+        * Ring has to be padded to a quad word. But because the command starts
+          with 7 bytes, pad only if there is an even number of ndwords
+        */
+       pad = !(ndwords % 2);
+
+       DRM_DEBUG("imageblit %dx%dx%d to (%d,%d)\n", image->width,
+                 image->height, image->depth, image->dx, image->dy);
+       DRM_DEBUG("nbytes: %d, ndwords: %d, pad: %d\n", nbytes, ndwords, pad);
+
+       tmp = (XY_MONO_SRC_COPY_IMM_BLT & 0xff) + ndwords;
+       cmd = (XY_MONO_SRC_COPY_IMM_BLT & ~0xff) | tmp;
+       offset = par->fb->offset;
+       dst_x1 = image->dx;
+       dst_y1 = image->dy;
+       dst_x2 = image->dx + image->width;
+       dst_y2 = image->dy + image->height;
+       rop_pitch_depth = BLT_ROP_GXCOPY | par->fb->pitch;
+
+       switch (par->fb->bits_per_pixel) {
+       case 8:
+               rop_pitch_depth |= BLT_DEPTH_8;
+               fg = image->fg_color;
+               bg = image->bg_color;
+               break;
+       case 16:
+               rop_pitch_depth |= BLT_DEPTH_16_565;
+               fg = par->fb->pseudo_palette[image->fg_color];
+               bg = par->fb->pseudo_palette[image->bg_color];
+               break;
+       case 32:
+               rop_pitch_depth |= BLT_DEPTH_32;
+               cmd |= XY_SRC_COPY_BLT_WRITE_ALPHA | XY_SRC_COPY_BLT_WRITE_RGB;
+               fg = par->fb->pseudo_palette[image->fg_color];
+               bg = par->fb->pseudo_palette[image->bg_color];
+               break;
+       default:
+               DRM_ERROR("unknown depth %d\n", par->fb->bits_per_pixel);
+               break;
+       }
+       
+       BEGIN_LP_RING(8 + ndwords);
+       OUT_RING(cmd);
+       OUT_RING(rop_pitch_depth);
+       OUT_RING((dst_y1 << 16) | (dst_x1 & 0xffff));
+       OUT_RING((dst_y2 << 16) | (dst_x2 & 0xffff));
+       OUT_RING(offset);
+       OUT_RING(bg);
+       OUT_RING(fg);
+       ix = iy = 0;
+       iw = ROUND_UP_TO(image->width, 8) / 8;
+       while (ndwords--) {
+               dat = 0;
+               for (j = 0; j < 2; ++j) {
+                       for (i = 0; i < 2; ++i) {
+                               if (ix != iw || i == 0)
+                                       dat |= image->data[iy*iw + ix++] << (i+j*2)*8;
+                       }
+                       if (ix == iw && iy != (image->height - 1)) {
+                               ix = 0;
+                               ++iy;
+                       }
+               }
+               OUT_RING(dat);
+       }
+       if (pad)
+               OUT_RING(MI_NOOP);
+       ADVANCE_LP_RING();
+}
+#endif
+static int intelfb_pan_display(struct fb_var_screeninfo *var,
+                              struct fb_info *info)
+{
+       struct intelfb_par *par = info->par;
+       struct drm_crtc *crtc = par->crtc;
+
+       DRM_DEBUG("\n");
+
+       /* TODO add check size and pos*/
+
+       /* re-attach fb */
+       if (!crtc->fb)
+               crtc->fb = par->fb;
+
+       drm_crtc_set_mode(crtc, &crtc->mode, var->xoffset, var->yoffset);
+
+       info->var.xoffset = var->xoffset;
+       info->var.yoffset = var->yoffset;
+
+       return 0;
+}
+
+static struct fb_ops intelfb_ops = {
+       .owner = THIS_MODULE,
+       //      .fb_open = intelfb_open,
+       //      .fb_read = intelfb_read,
+       //      .fb_write = intelfb_write,
+       //      .fb_release = intelfb_release,
+       //      .fb_ioctl = intelfb_ioctl,
+       .fb_check_var = intelfb_check_var,
+       .fb_set_par = intelfb_set_par,
+       .fb_setcolreg = intelfb_setcolreg,
+       .fb_fillrect = cfb_fillrect,
+       .fb_copyarea = cfb_copyarea, //intelfb_copyarea,
+       .fb_imageblit = cfb_imageblit, //intelfb_imageblit,
+       .fb_pan_display = intelfb_pan_display,
+};
+
+/**
+ * Curretly it is assumed that the old framebuffer is reused.
+ *
+ * LOCKING
+ * caller should hold the mode config lock.
+ *
+ */
+int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
+{
+       struct fb_info *info;
+       struct drm_framebuffer *fb;
+       struct drm_display_mode *mode = crtc->desired_mode;
+
+       fb = crtc->fb;
+       if (!fb)
+               return 1;
+
+       info = fb->fbdev;
+       if (!info)
+               return 1;
+
+       if (!mode)
+               return 1;
+
+       info->var.xres = mode->hdisplay;
+       info->var.right_margin = mode->hsync_start - mode->hdisplay;
+       info->var.hsync_len = mode->hsync_end - mode->hsync_start;
+       info->var.left_margin = mode->htotal - mode->hsync_end;
+       info->var.yres = mode->vdisplay;
+       info->var.lower_margin = mode->vsync_start - mode->vdisplay;
+       info->var.vsync_len = mode->vsync_end - mode->vsync_start;
+       info->var.upper_margin = mode->vtotal - mode->vsync_end;
+       info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100;
+       /* avoid overflow */
+       info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
+
+       return 0;
+}
+EXPORT_SYMBOL(intelfb_resize);
+
+int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc)
+{
+       struct fb_info *info;
+       struct intelfb_par *par;
+       struct device *device = &dev->pdev->dev; 
+       struct drm_framebuffer *fb;
+       struct drm_display_mode *mode = crtc->desired_mode;
+       struct drm_buffer_object *fbo = NULL;
+       int ret;
+
+       info = framebuffer_alloc(sizeof(struct intelfb_par), device);
+       if (!info){
+               return -EINVAL;
+       }
+
+       fb = drm_framebuffer_create(dev);
+       if (!fb) {
+               framebuffer_release(info);
+               DRM_ERROR("failed to allocate fb.\n");
+               return -EINVAL;
+       }
+       crtc->fb = fb;
+
+       /* To allow resizeing without swapping buffers */
+       fb->width = 2048;/* crtc->desired_mode->hdisplay; */
+       fb->height = 2048;/* crtc->desired_mode->vdisplay; */
+
+       fb->bits_per_pixel = 32;
+       fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8);
+       fb->depth = 24;
+       ret = drm_buffer_object_create(dev, fb->pitch * fb->height * 4, 
+                                      drm_bo_type_kernel,
+                                      DRM_BO_FLAG_READ |
+                                      DRM_BO_FLAG_WRITE |
+                                      DRM_BO_FLAG_MEM_TT |
+                                      DRM_BO_FLAG_MEM_VRAM |
+                                      DRM_BO_FLAG_NO_EVICT,
+                                      DRM_BO_HINT_DONT_FENCE, 0, 0,
+                                      &fbo);
+       if (ret || !fbo) {
+               printk(KERN_ERR "failed to allocate framebuffer\n");
+               drm_framebuffer_destroy(fb);
+               framebuffer_release(info);
+               return -EINVAL;
+       }
+
+       fb->bo = fbo;
+       printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width,
+                      fb->height, fbo->offset, fbo);
+
+
+       fb->fbdev = info;
+               
+       par = info->par;
+
+       par->dev = dev;
+       par->crtc = crtc;
+       par->fb = fb;
+
+       info->fbops = &intelfb_ops;
+
+       strcpy(info->fix.id, "intelfb");
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+       info->fix.visual = FB_VISUAL_TRUECOLOR;
+       info->fix.type_aux = 0;
+       info->fix.xpanstep = 1; /* doing it in hw */
+       info->fix.ypanstep = 1; /* doing it in hw */
+       info->fix.ywrapstep = 0;
+       info->fix.accel = FB_ACCEL_I830;
+       info->fix.type_aux = 0;
+       if (IS_I9XX(dev)) {
+               info->fix.mmio_start = pci_resource_start(dev->pdev, 0);
+               info->fix.mmio_len = pci_resource_len(dev->pdev, 0);
+       } else {
+               info->fix.mmio_start = pci_resource_start(dev->pdev, 1);
+               info->fix.mmio_len = pci_resource_len(dev->pdev, 1);
+       }
+
+       info->fix.line_length = fb->pitch;
+       info->fix.smem_start = fb->bo->offset + dev->mode_config.fb_base;
+       info->fix.smem_len = info->fix.line_length * fb->height;
+
+       info->flags = FBINFO_DEFAULT;
+
+       ret = drm_bo_kmap(fb->bo, 0, fb->bo->num_pages, &fb->kmap);
+       if (ret)
+               DRM_ERROR("error mapping fb: %d\n", ret);
+  
+       info->screen_base = fb->kmap.virtual;
+       info->screen_size = info->fix.smem_len; /* FIXME */
+       info->pseudo_palette = fb->pseudo_palette;
+       info->var.xres_virtual = fb->width;
+       info->var.yres_virtual = fb->height;
+       info->var.bits_per_pixel = fb->bits_per_pixel;
+       info->var.xoffset = 0;
+       info->var.yoffset = 0;
+       info->var.activate = FB_ACTIVATE_NOW;
+       info->var.height = -1;
+       info->var.width = -1;
+
+        info->var.xres = mode->hdisplay;
+        info->var.right_margin = mode->hsync_start - mode->hdisplay;
+        info->var.hsync_len = mode->hsync_end - mode->hsync_start;
+        info->var.left_margin = mode->htotal - mode->hsync_end;
+        info->var.yres = mode->vdisplay;
+        info->var.lower_margin = mode->vsync_start - mode->vdisplay;
+        info->var.vsync_len = mode->vsync_end - mode->vsync_start;
+       info->var.upper_margin = mode->vtotal - mode->vsync_end;
+       info->var.pixclock = KHZ2PICOS(mode->clock);
+
+       if (mode->flags & V_PHSYNC)
+               info->var.sync |= FB_SYNC_HOR_HIGH_ACT;
+
+       if (mode->flags & V_PVSYNC)
+               info->var.sync |= FB_SYNC_VERT_HIGH_ACT;
+
+       if (mode->flags & V_INTERLACE)
+               info->var.vmode = FB_VMODE_INTERLACED;
+       else if (mode->flags & V_DBLSCAN)
+               info->var.vmode = FB_VMODE_DOUBLE;
+       else
+               info->var.vmode = FB_VMODE_NONINTERLACED;
+
+       info->pixmap.size = 64*1024;
+       info->pixmap.buf_align = 8;
+       info->pixmap.access_align = 32;
+       info->pixmap.flags = FB_PIXMAP_SYSTEM;
+       info->pixmap.scan_align = 1;
+
+       DRM_DEBUG("fb depth is %d\n", fb->depth);
+       DRM_DEBUG("   pitch is %d\n", fb->pitch);
+       switch(fb->depth) {
+       case 8:
+                info->var.red.offset = 0;
+                info->var.green.offset = 0;
+                info->var.blue.offset = 0;
+                info->var.red.length = 8; /* 8bit DAC */
+                info->var.green.length = 8;
+                info->var.blue.length = 8;
+                info->var.transp.offset = 0;
+                info->var.transp.length = 0;
+                break;
+       case 15:
+                info->var.red.offset = 10;
+                info->var.green.offset = 5;
+                info->var.blue.offset = 0;
+                info->var.red.length = info->var.green.length =
+                        info->var.blue.length = 5;
+                info->var.transp.offset = 15;
+                info->var.transp.length = 1;
+                break;
+       case 16:
+                info->var.red.offset = 11;
+                info->var.green.offset = 5;
+                info->var.blue.offset = 0;
+                info->var.red.length = 5;
+                info->var.green.length = 6;
+                info->var.blue.length = 5;
+                info->var.transp.offset = 0;
+               break;
+       case 24:
+                info->var.red.offset = 16;
+                info->var.green.offset = 8;
+                info->var.blue.offset = 0;
+                info->var.red.length = info->var.green.length =
+                        info->var.blue.length = 8;
+                info->var.transp.offset = 0;
+                info->var.transp.length = 0;
+                break;
+       case 32:
+               info->var.red.offset = 16;
+               info->var.green.offset = 8;
+               info->var.blue.offset = 0;
+               info->var.red.length = info->var.green.length =
+                       info->var.blue.length = 8;
+               info->var.transp.offset = 24;
+               info->var.transp.length = 8;
+               break;
+       default:
+               break;
+       }
+
+       if (register_framebuffer(info) < 0)
+               return -EINVAL;
+
+       printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+              info->fix.id);
+       return 0;
+}
+EXPORT_SYMBOL(intelfb_probe);
+
+int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc)
+{
+       struct drm_framebuffer *fb = crtc->fb;
+       struct fb_info *info = fb->fbdev;
+       
+       if (info) {
+               unregister_framebuffer(info);
+               drm_bo_kunmap(&fb->kmap);
+               drm_bo_usage_deref_unlocked(&fb->bo);
+               drm_framebuffer_destroy(fb);
+               framebuffer_release(info);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(intelfb_remove);
+MODULE_LICENSE("GPL");
diff --git a/linux-core/intel_i2c.c b/linux-core/intel_i2c.c
new file mode 100644 (file)
index 0000000..efcbf65
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright Â© 2006-2007 Intel Corporation
+ *
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ */
+/*
+ * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+#include "drmP.h"
+#include "drm.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+/*
+ * Intel GPIO access functions
+ */
+
+#define I2C_RISEFALL_TIME 20
+
+static int get_clock(void *data)
+{
+       struct intel_i2c_chan *chan = data;
+       struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
+       u32 val;
+
+       val = I915_READ(chan->reg);
+       return ((val & GPIO_CLOCK_VAL_IN) != 0);
+}
+
+static int get_data(void *data)
+{
+       struct intel_i2c_chan *chan = data;
+       struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
+       u32 val;
+
+       val = I915_READ(chan->reg);
+       return ((val & GPIO_DATA_VAL_IN) != 0);
+}
+
+static void set_clock(void *data, int state_high)
+{
+       struct intel_i2c_chan *chan = data;
+       struct drm_device *dev = chan->drm_dev;
+       struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
+       u32 reserved = 0, clock_bits;
+
+       /* On most chips, these bits must be preserved in software. */
+       if (!IS_I830(dev) && !IS_845G(dev))
+               reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE |
+                                                  GPIO_CLOCK_PULLUP_DISABLE);
+
+       if (state_high)
+               clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK;
+       else
+               clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK |
+                       GPIO_CLOCK_VAL_MASK;
+       I915_WRITE(chan->reg, reserved | clock_bits);
+       udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */
+}
+
+static void set_data(void *data, int state_high)
+{
+       struct intel_i2c_chan *chan = data;
+       struct drm_device *dev = chan->drm_dev;
+       struct drm_i915_private *dev_priv = chan->drm_dev->dev_private;
+       u32 reserved = 0, data_bits;
+
+       /* On most chips, these bits must be preserved in software. */
+       if (!IS_I830(dev) && !IS_845G(dev))
+               reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE |
+                                                  GPIO_CLOCK_PULLUP_DISABLE);
+
+       if (state_high)
+               data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK;
+       else
+               data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK |
+                       GPIO_DATA_VAL_MASK;
+
+       I915_WRITE(chan->reg, reserved | data_bits);
+       udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */
+}
+
+/**
+ * intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg
+ * @dev: DRM device
+ * @output: driver specific output device
+ * @reg: GPIO reg to use
+ * @name: name for this bus
+ *
+ * Creates and registers a new i2c bus with the Linux i2c layer, for use
+ * in output probing and control (e.g. DDC or SDVO control functions).
+ *
+ * Possible values for @reg include:
+ *   %GPIOA
+ *   %GPIOB
+ *   %GPIOC
+ *   %GPIOD
+ *   %GPIOE
+ *   %GPIOF
+ *   %GPIOG
+ *   %GPIOH
+ * see PRM for details on how these different busses are used.
+ */
+struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg,
+                                       const char *name)
+{
+       struct intel_i2c_chan *chan;
+
+       chan = kzalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL);
+       if (!chan)
+               goto out_free;
+
+       chan->drm_dev = dev;
+       chan->reg = reg;
+       snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name);
+       chan->adapter.owner = THIS_MODULE;
+#ifndef I2C_HW_B_INTELFB
+#define I2C_HW_B_INTELFB I2C_HW_B_I810
+#endif
+       chan->adapter.id = I2C_HW_B_INTELFB;
+       chan->adapter.algo_data = &chan->algo;
+       chan->adapter.dev.parent = &dev->pdev->dev;
+       chan->algo.setsda = set_data;
+       chan->algo.setscl = set_clock;
+       chan->algo.getsda = get_data;
+       chan->algo.getscl = get_clock;
+       chan->algo.udelay = 20;
+       chan->algo.timeout = usecs_to_jiffies(2200);
+       chan->algo.data = chan;
+
+       i2c_set_adapdata(&chan->adapter, chan);
+
+       if(i2c_bit_add_bus(&chan->adapter))
+               goto out_free;
+
+       /* JJJ:  raise SCL and SDA? */
+       set_data(chan, 1);
+       set_clock(chan, 1);
+       udelay(20);
+
+       return chan;
+
+out_free:
+       kfree(chan);
+       return NULL;
+}
+
+/**
+ * intel_i2c_destroy - unregister and free i2c bus resources
+ * @output: channel to free
+ *
+ * Unregister the adapter from the i2c layer, then free the structure.
+ */
+void intel_i2c_destroy(struct intel_i2c_chan *chan)
+{
+       if (!chan)
+               return;
+
+       i2c_del_adapter(&chan->adapter);
+       kfree(chan);
+}
+
+       
+       
diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c
new file mode 100644 (file)
index 0000000..80f77af
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+ * Copyright Â© 2006-2007 Intel Corporation
+ * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
+ *
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ *      Dave Airlie <airlied@linux.ie>
+ *      Jesse Barnes <jesse.barnes@intel.com>
+ */
+
+#include <linux/i2c.h>
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "drm_edid.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+/**
+ * Sets the backlight level.
+ *
+ * \param level backlight level, from 0 to intel_lvds_get_max_backlight().
+ */
+static void intel_lvds_set_backlight(struct drm_device *dev, int level)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 blc_pwm_ctl;
+
+       blc_pwm_ctl = I915_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+       I915_WRITE(BLC_PWM_CTL, (blc_pwm_ctl |
+                                (level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
+}
+
+/**
+ * Returns the maximum level of the backlight duty cycle field.
+ */
+static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+    
+       return ((I915_READ(BLC_PWM_CTL) & BACKLIGHT_MODULATION_FREQ_MASK) >>
+               BACKLIGHT_MODULATION_FREQ_SHIFT) * 2;
+}
+
+/**
+ * Sets the power state for the panel.
+ */
+static void intel_lvds_set_power(struct drm_device *dev, bool on)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 pp_status;
+
+       if (on) {
+               I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) |
+                          POWER_TARGET_ON);
+               do {
+                       pp_status = I915_READ(PP_STATUS);
+               } while ((pp_status & PP_ON) == 0);
+
+               intel_lvds_set_backlight(dev, dev_priv->backlight_duty_cycle);
+       } else {
+               intel_lvds_set_backlight(dev, 0);
+
+               I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) &
+                          ~POWER_TARGET_ON);
+               do {
+                       pp_status = I915_READ(PP_STATUS);
+               } while (pp_status & PP_ON);
+       }
+}
+
+static void intel_lvds_dpms(struct drm_output *output, int mode)
+{
+       struct drm_device *dev = output->dev;
+
+       if (mode == DPMSModeOn)
+               intel_lvds_set_power(dev, true);
+       else
+               intel_lvds_set_power(dev, false);
+
+       /* XXX: We never power down the LVDS pairs. */
+}
+
+static void intel_lvds_save(struct drm_output *output)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       dev_priv->savePP_ON = I915_READ(LVDSPP_ON);
+       dev_priv->savePP_OFF = I915_READ(LVDSPP_OFF);
+       dev_priv->savePP_CONTROL = I915_READ(PP_CONTROL);
+       dev_priv->savePP_CYCLE = I915_READ(PP_CYCLE);
+       dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
+       dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
+                                      BACKLIGHT_DUTY_CYCLE_MASK);
+
+       /*
+        * If the light is off at server startup, just make it full brightness
+        */
+       if (dev_priv->backlight_duty_cycle == 0)
+               dev_priv->backlight_duty_cycle =
+                       intel_lvds_get_max_backlight(dev);
+}
+
+static void intel_lvds_restore(struct drm_output *output)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE(BLC_PWM_CTL, dev_priv->saveBLC_PWM_CTL);
+       I915_WRITE(LVDSPP_ON, dev_priv->savePP_ON);
+       I915_WRITE(LVDSPP_OFF, dev_priv->savePP_OFF);
+       I915_WRITE(PP_CYCLE, dev_priv->savePP_CYCLE);
+       I915_WRITE(PP_CONTROL, dev_priv->savePP_CONTROL);
+       if (dev_priv->savePP_CONTROL & POWER_TARGET_ON)
+               intel_lvds_set_power(dev, true);
+       else
+               intel_lvds_set_power(dev, false);
+}
+
+static int intel_lvds_mode_valid(struct drm_output *output,
+                                struct drm_display_mode *mode)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode;
+
+       if (fixed_mode) {
+               if (mode->hdisplay > fixed_mode->hdisplay)
+                       return MODE_PANEL;
+               if (mode->vdisplay > fixed_mode->vdisplay)
+                       return MODE_PANEL;
+       }
+
+       return MODE_OK;
+}
+
+static bool intel_lvds_mode_fixup(struct drm_output *output,
+                                 struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = output->crtc->driver_private;
+       struct drm_output *tmp_output;
+
+       /* Should never happen!! */
+       if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
+               printk(KERN_ERR "Can't support LVDS on pipe A\n");
+               return false;
+       }
+
+       /* Should never happen!! */
+       list_for_each_entry(tmp_output, &dev->mode_config.output_list, head) {
+               if (tmp_output != output && tmp_output->crtc == output->crtc) {
+                       printk(KERN_ERR "Can't enable LVDS and another "
+                              "output on the same pipe\n");
+                       return false;
+               }
+       }
+
+       /*
+        * If we have timings from the BIOS for the panel, put them in
+        * to the adjusted mode.  The CRTC will be set up for this mode,
+        * with the panel scaling set up to source from the H/VDisplay
+        * of the original mode.
+        */
+       if (dev_priv->panel_fixed_mode != NULL) {
+               adjusted_mode->hdisplay = dev_priv->panel_fixed_mode->hdisplay;
+               adjusted_mode->hsync_start =
+                       dev_priv->panel_fixed_mode->hsync_start;
+               adjusted_mode->hsync_end =
+                       dev_priv->panel_fixed_mode->hsync_end;
+               adjusted_mode->htotal = dev_priv->panel_fixed_mode->htotal;
+               adjusted_mode->vdisplay = dev_priv->panel_fixed_mode->vdisplay;
+               adjusted_mode->vsync_start =
+                       dev_priv->panel_fixed_mode->vsync_start;
+               adjusted_mode->vsync_end =
+                       dev_priv->panel_fixed_mode->vsync_end;
+               adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal;
+               adjusted_mode->clock = dev_priv->panel_fixed_mode->clock;
+               drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
+       }
+
+       /*
+        * XXX: It would be nice to support lower refresh rates on the
+        * panels to reduce power consumption, and perhaps match the
+        * user's requested refresh rate.
+        */
+
+       return true;
+}
+
+static void intel_lvds_prepare(struct drm_output *output)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       dev_priv->saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
+       dev_priv->backlight_duty_cycle = (dev_priv->saveBLC_PWM_CTL &
+                                      BACKLIGHT_DUTY_CYCLE_MASK);
+
+       intel_lvds_set_power(dev, false);
+}
+
+static void intel_lvds_commit( struct drm_output *output)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->backlight_duty_cycle == 0)
+               dev_priv->backlight_duty_cycle =
+                       intel_lvds_get_max_backlight(dev);
+
+       intel_lvds_set_power(dev, true);
+}
+
+static void intel_lvds_mode_set(struct drm_output *output,
+                               struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = output->crtc->driver_private;
+       u32 pfit_control;
+
+       /*
+        * The LVDS pin pair will already have been turned on in the
+        * intel_crtc_mode_set since it has a large impact on the DPLL
+        * settings.
+        */
+
+       /*
+        * Enable automatic panel scaling so that non-native modes fill the
+        * screen.  Should be enabled before the pipe is enabled, according to
+        * register description and PRM.
+        */
+       if (mode->hdisplay != adjusted_mode->hdisplay ||
+           mode->vdisplay != adjusted_mode->vdisplay)
+               pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE |
+                               HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR |
+                               HORIZ_INTERP_BILINEAR);
+       else
+               pfit_control = 0;
+
+       if (!IS_I965G(dev)) {
+               if (dev_priv->panel_wants_dither)
+                       pfit_control |= PANEL_8TO6_DITHER_ENABLE;
+       }
+       else
+               pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT;
+
+       I915_WRITE(PFIT_CONTROL, pfit_control);
+}
+
+/**
+ * Detect the LVDS connection.
+ *
+ * This always returns OUTPUT_STATUS_CONNECTED.  This output should only have
+ * been set up if the LVDS was actually connected anyway.
+ */
+static enum drm_output_status intel_lvds_detect(struct drm_output *output)
+{
+       return output_status_connected;
+}
+
+/**
+ * Return the list of DDC modes if available, or the BIOS fixed mode otherwise.
+ */
+static int intel_lvds_get_modes(struct drm_output *output)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret = 0;
+
+       ret = intel_ddc_get_modes(output);
+
+       if (ret)
+               return ret;
+
+       /* Didn't get an EDID */
+       if (!output->monitor_info) {
+               struct drm_display_info *dspinfo;
+               dspinfo = kzalloc(sizeof(*output->monitor_info), GFP_KERNEL);
+               if (!dspinfo)
+                       goto out;
+
+               /* Set wide sync ranges so we get all modes
+                * handed to valid_mode for checking
+                */
+               dspinfo->min_vfreq = 0;
+               dspinfo->max_vfreq = 200;
+               dspinfo->min_hfreq = 0;
+               dspinfo->max_hfreq = 200;
+               output->monitor_info = dspinfo;
+       }
+
+out:
+       if (dev_priv->panel_fixed_mode != NULL) {
+               struct drm_display_mode *mode =
+                       drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
+               drm_mode_probed_add(output, mode);
+               return 1;
+       }
+
+       return 0;
+}
+
+/**
+ * intel_lvds_destroy - unregister and free LVDS structures
+ * @output: output to free
+ *
+ * Unregister the DDC bus for this output then free the driver private
+ * structure.
+ */
+static void intel_lvds_destroy(struct drm_output *output)
+{
+       struct intel_output *intel_output = output->driver_private;
+
+       intel_i2c_destroy(intel_output->ddc_bus);
+       kfree(output->driver_private);
+}
+
+static const struct drm_output_funcs intel_lvds_output_funcs = {
+       .dpms = intel_lvds_dpms,
+       .save = intel_lvds_save,
+       .restore = intel_lvds_restore,
+       .mode_valid = intel_lvds_mode_valid,
+       .mode_fixup = intel_lvds_mode_fixup,
+       .prepare = intel_lvds_prepare,
+       .mode_set = intel_lvds_mode_set,
+       .commit = intel_lvds_commit,
+       .detect = intel_lvds_detect,
+       .get_modes = intel_lvds_get_modes,
+       .cleanup = intel_lvds_destroy
+};
+
+/**
+ * intel_lvds_init - setup LVDS outputs on this device
+ * @dev: drm device
+ *
+ * Create the output, register the LVDS DDC bus, and try to figure out what
+ * modes we can display on the LVDS panel (if present).
+ */
+void intel_lvds_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_output *output;
+       struct intel_output *intel_output;
+       struct drm_display_mode *scan; /* *modes, *bios_mode; */
+       struct drm_crtc *crtc;
+       u32 lvds;
+       int pipe;
+
+       output = drm_output_create(dev, &intel_lvds_output_funcs,
+                                  DRM_MODE_OUTPUT_LVDS);
+       if (!output)
+               return;
+
+       intel_output = kmalloc(sizeof(struct intel_output), GFP_KERNEL);
+       if (!intel_output) {
+               drm_output_destroy(output);
+               return;
+       }
+
+       intel_output->type = INTEL_OUTPUT_LVDS;
+       output->driver_private = intel_output;
+       output->subpixel_order = SubPixelHorizontalRGB;
+       output->interlace_allowed = FALSE;
+       output->doublescan_allowed = FALSE;
+
+       /* Set up the DDC bus. */
+       intel_output->ddc_bus = intel_i2c_create(dev, GPIOC, "LVDSDDC_C");
+       if (!intel_output->ddc_bus) {
+               dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
+                          "failed.\n");
+               return;
+       }
+
+       /*
+        * Attempt to get the fixed panel mode from DDC.  Assume that the
+        * preferred mode is the right one.
+        */
+       intel_ddc_get_modes(output);
+
+       list_for_each_entry(scan, &output->probed_modes, head) {
+               if (scan->type & DRM_MODE_TYPE_PREFERRED) {
+                       dev_priv->panel_fixed_mode = 
+                               drm_mode_duplicate(dev, scan);
+                       goto out; /* FIXME: check for quirks */
+               }
+       }
+
+       /*
+        * If we didn't get EDID, try checking if the panel is already turned
+        * on.  If so, assume that whatever is currently programmed is the
+        * correct mode.
+        */
+       lvds = I915_READ(LVDS);
+       pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
+       crtc = intel_get_crtc_from_pipe(dev, pipe);
+               
+       if (crtc && (lvds & LVDS_PORT_EN)) {
+               dev_priv->panel_fixed_mode = intel_crtc_mode_get(dev, crtc);
+               if (dev_priv->panel_fixed_mode) {
+                       dev_priv->panel_fixed_mode->type |=
+                               DRM_MODE_TYPE_PREFERRED;
+                       goto out; /* FIXME: check for quirks */
+               }
+       }
+
+       /* If we still don't have a mode after all that, give up. */
+       if (!dev_priv->panel_fixed_mode)
+               goto failed;
+
+       /* FIXME: probe the BIOS for modes and check for LVDS quirks */
+#if 0
+       /* Get the LVDS fixed mode out of the BIOS.  We should support LVDS
+        * with the BIOS being unavailable or broken, but lack the
+        * configuration options for now.
+        */
+       bios_mode = intel_bios_get_panel_mode(pScrn);
+       if (bios_mode != NULL) {
+               if (dev_priv->panel_fixed_mode != NULL) {
+                       if (dev_priv->debug_modes &&
+                           !xf86ModesEqual(dev_priv->panel_fixed_mode,
+                                           bios_mode))
+                       {
+                               xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                                          "BIOS panel mode data doesn't match probed data, "
+                                          "continuing with probed.\n");
+                               xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS mode:\n");
+                               xf86PrintModeline(pScrn->scrnIndex, bios_mode);
+                               xf86DrvMsg(pScrn->scrnIndex, X_INFO, "probed mode:\n");
+                               xf86PrintModeline(pScrn->scrnIndex, dev_priv->panel_fixed_mode);
+                               xfree(bios_mode->name);
+                               xfree(bios_mode);
+                       }
+               }  else {
+                       dev_priv->panel_fixed_mode = bios_mode;
+               }
+       } else {
+               xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                          "Couldn't detect panel mode.  Disabling panel\n");
+               goto disable_exit;
+       }
+
+       /*
+        * Blacklist machines with BIOSes that list an LVDS panel without
+        * actually having one.
+        */
+       if (dev_priv->PciInfo->chipType == PCI_CHIP_I945_GM) {
+               /* aopen mini pc */
+               if (dev_priv->PciInfo->subsysVendor == 0xa0a0)
+                       goto disable_exit;
+
+               if ((dev_priv->PciInfo->subsysVendor == 0x8086) &&
+                   (dev_priv->PciInfo->subsysCard == 0x7270)) {
+                       /* It's a Mac Mini or Macbook Pro.
+                        *
+                        * Apple hardware is out to get us.  The macbook pro
+                        * has a real LVDS panel, but the mac mini does not,
+                        * and they have the same device IDs.  We'll
+                        * distinguish by panel size, on the assumption
+                        * that Apple isn't about to make any machines with an
+                        * 800x600 display.
+                        */
+
+                       if (dev_priv->panel_fixed_mode != NULL &&
+                           dev_priv->panel_fixed_mode->HDisplay == 800 &&
+                           dev_priv->panel_fixed_mode->VDisplay == 600)
+                       {
+                               xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+                                          "Suspected Mac Mini, ignoring the LVDS\n");
+                               goto disable_exit;
+                       }
+               }
+       }
+
+#endif
+
+out:
+       drm_output_attach_property(output, dev->mode_config.connector_type_property, ConnectorLVDS);
+       return;
+
+failed:
+        DRM_DEBUG("No LVDS modes found, disabling.\n");
+       drm_output_destroy(output); /* calls intel_lvds_destroy above */
+}
diff --git a/linux-core/intel_modes.c b/linux-core/intel_modes.c
new file mode 100644 (file)
index 0000000..f8bf496
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
+ * Copyright (c) 2007 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/fb.h>
+#include "drmP.h"
+#include "intel_drv.h"
+
+/**
+ * intel_ddc_probe
+ *
+ */
+bool intel_ddc_probe(struct drm_output *output)
+{
+       struct intel_output *intel_output = output->driver_private;
+       u8 out_buf[] = { 0x0, 0x0};
+       u8 buf[2];
+       int ret;
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = 0x50,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = out_buf,
+               },
+               {
+                       .addr = 0x50,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = buf,
+               }
+       };
+
+       ret = i2c_transfer(&intel_output->ddc_bus->adapter, msgs, 2);
+       if (ret == 2)
+               return true;
+
+       return false;
+}
+
+/**
+ * intel_ddc_get_modes - get modelist from monitor
+ * @output: DRM output device to use
+ *
+ * Fetch the EDID information from @output using the DDC bus.
+ */
+int intel_ddc_get_modes(struct drm_output *output)
+{
+       struct intel_output *intel_output = output->driver_private;
+       struct edid *edid;
+       int ret = 0;
+
+       edid = drm_get_edid(output, &intel_output->ddc_bus->adapter);
+       if (edid) {
+               drm_mode_output_update_edid_property(output, edid);
+               ret = drm_add_edid_modes(output, edid);
+               kfree(edid);
+       }
+       return ret;
+}
diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c
new file mode 100644 (file)
index 0000000..3887df0
--- /dev/null
@@ -0,0 +1,1168 @@
+/*
+ * Copyright Â© 2006-2007 Intel Corporation
+ *
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ */
+/*
+ * Copyright 2006 Dave Airlie <airlied@linux.ie>
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+#include "intel_sdvo_regs.h"
+
+struct intel_sdvo_priv {
+       struct intel_i2c_chan *i2c_bus;
+       int slaveaddr;
+       int output_device;
+
+       u16 active_outputs;
+
+       struct intel_sdvo_caps caps;
+       int pixel_clock_min, pixel_clock_max;
+
+       int save_sdvo_mult;
+       u16 save_active_outputs;
+       struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2;
+       struct intel_sdvo_dtd save_output_dtd[16];
+       u32 save_SDVOX;
+       int hotplug_enabled;
+};
+
+/**
+ * Writes the SDVOB or SDVOC with the given value, but always writes both
+ * SDVOB and SDVOC to work around apparent hardware issues (according to
+ * comments in the BIOS).
+ */
+void intel_sdvo_write_sdvox(struct drm_output *output, u32 val)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_sdvo_priv   *sdvo_priv = intel_output->dev_priv;
+       u32 bval = val, cval = val;
+       int i;
+
+       if (sdvo_priv->output_device == SDVOB) {
+               cval = I915_READ(SDVOC);
+
+               if (sdvo_priv->hotplug_enabled)
+                       bval = bval | (1 << 26);
+       } else {
+               bval = I915_READ(SDVOB);
+
+               if (sdvo_priv->hotplug_enabled)
+                       cval = cval | (1 << 26);
+       }
+       /*
+        * Write the registers twice for luck. Sometimes,
+        * writing them only once doesn't appear to 'stick'.
+        * The BIOS does this too. Yay, magic
+        */
+       for (i = 0; i < 2; i++)
+       {
+               I915_WRITE(SDVOB, bval);
+               I915_READ(SDVOB);
+               I915_WRITE(SDVOC, cval);
+               I915_READ(SDVOC);
+       }
+}
+
+static bool intel_sdvo_read_byte(struct drm_output *output, u8 addr,
+                                u8 *ch)
+{
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       u8 out_buf[2];
+       u8 buf[2];
+       int ret;
+
+       struct i2c_msg msgs[] = {
+               { 
+                       .addr = sdvo_priv->i2c_bus->slave_addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = out_buf,
+               }, 
+               {
+                       .addr = sdvo_priv->i2c_bus->slave_addr,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = buf,
+               }
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = 0;
+
+       if ((ret = i2c_transfer(&sdvo_priv->i2c_bus->adapter, msgs, 2)) == 2)
+       {
+//             DRM_DEBUG("got back from addr %02X = %02x\n", out_buf[0], buf[0]); 
+               *ch = buf[0];
+               return true;
+       }
+
+       DRM_DEBUG("i2c transfer returned %d\n", ret);
+       return false;
+}
+
+
+static bool intel_sdvo_read_byte_quiet(struct drm_output *output, int addr,
+                                      u8 *ch)
+{
+       return true;
+
+}
+
+static bool intel_sdvo_write_byte(struct drm_output *output, int addr,
+                                 u8 ch)
+{
+       struct intel_output *intel_output = output->driver_private;
+       u8 out_buf[2];
+       struct i2c_msg msgs[] = {
+               { 
+                       .addr = intel_output->i2c_bus->slave_addr,
+                       .flags = 0,
+                       .len = 2,
+                       .buf = out_buf,
+               }
+       };
+
+       out_buf[0] = addr;
+       out_buf[1] = ch;
+
+       if (i2c_transfer(&intel_output->i2c_bus->adapter, msgs, 1) == 1)
+       {
+               return true;
+       }
+       return false;
+}
+
+#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}
+/** Mapping of command numbers to names, for debug output */
+const static struct _sdvo_cmd_name {
+    u8 cmd;
+    char *name;
+} sdvo_cmd_names[] = {
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_RESET),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_DEVICE_CAPS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_FIRMWARE_REV),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TRAINED_INPUTS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_OUTPUTS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_OUTPUTS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_IN_OUT_MAP),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_IN_OUT_MAP),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ATTACHED_DISPLAYS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HOT_PLUG_SUPPORT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_ACTIVE_HOT_PLUG),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_ACTIVE_HOT_PLUG),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_INPUT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TARGET_OUTPUT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART1),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_TIMINGS_PART2),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART2),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_INPUT_TIMINGS_PART1),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART1),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_OUTPUT_TIMINGS_PART2),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART1),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_TIMINGS_PART2),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_CLOCK_RATE_MULT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CLOCK_RATE_MULT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_SUPPORTED_TV_FORMATS),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_TV_FORMAT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_FORMAT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_TV_RESOLUTION_SUPPORT),
+    SDVO_CMD_NAME_ENTRY(SDVO_CMD_SET_CONTROL_BUS_SWITCH),
+};
+
+#define SDVO_NAME(dev_priv) ((dev_priv)->output_device == SDVOB ? "SDVOB" : "SDVOC")
+#define SDVO_PRIV(output)   ((struct intel_sdvo_priv *) (output)->dev_priv)
+
+static void intel_sdvo_write_cmd(struct drm_output *output, u8 cmd,
+                                void *args, int args_len)
+{
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       int i;
+
+        if (1) {
+                DRM_DEBUG("%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd);
+                for (i = 0; i < args_len; i++)
+                        printk("%02X ", ((u8 *)args)[i]);
+                for (; i < 8; i++)
+                        printk("   ");
+                for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) {
+                        if (cmd == sdvo_cmd_names[i].cmd) {
+                                printk("(%s)", sdvo_cmd_names[i].name);
+                                break;
+                        }
+                }
+                if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0]))
+                        printk("(%02X)",cmd);
+                printk("\n");
+        }
+                        
+       for (i = 0; i < args_len; i++) {
+               intel_sdvo_write_byte(output, SDVO_I2C_ARG_0 - i, ((u8*)args)[i]);
+       }
+
+       intel_sdvo_write_byte(output, SDVO_I2C_OPCODE, cmd);
+}
+
+static const char *cmd_status_names[] = {
+       "Power on",
+       "Success",
+       "Not supported",
+       "Invalid arg",
+       "Pending",
+       "Target not specified",
+       "Scaling not supported"
+};
+
+static u8 intel_sdvo_read_response(struct drm_output *output, void *response,
+                                  int response_len)
+{
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       int i;
+       u8 status;
+       u8 retry = 50;
+
+       while (retry--) {
+               /* Read the command response */
+               for (i = 0; i < response_len; i++) {
+                       intel_sdvo_read_byte(output, SDVO_I2C_RETURN_0 + i,
+                                    &((u8 *)response)[i]);
+               }
+
+               /* read the return status */
+               intel_sdvo_read_byte(output, SDVO_I2C_CMD_STATUS, &status);
+
+               if (1) {
+                       DRM_DEBUG("%s: R: ", SDVO_NAME(sdvo_priv));
+                               for (i = 0; i < response_len; i++)
+                               printk("%02X ", ((u8 *)response)[i]);
+                       for (; i < 8; i++)
+                               printk("   ");
+                       if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
+                               printk("(%s)", cmd_status_names[status]);
+                       else
+                               printk("(??? %d)", status);
+                       printk("\n");
+               }
+
+               if (status != SDVO_CMD_STATUS_PENDING)
+                       return status;
+
+               mdelay(50);
+       }
+
+       return status;
+}
+
+int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
+{
+       if (mode->clock >= 100000)
+               return 1;
+       else if (mode->clock >= 50000)
+               return 2;
+       else
+               return 4;
+}
+
+/**
+ * Don't check status code from this as it switches the bus back to the
+ * SDVO chips which defeats the purpose of doing a bus switch in the first
+ * place.
+ */
+void intel_sdvo_set_control_bus_switch(struct drm_output *output, u8 target)
+{
+       intel_sdvo_write_cmd(output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1);
+}
+
+static bool intel_sdvo_set_target_input(struct drm_output *output, bool target_0, bool target_1)
+{
+       struct intel_sdvo_set_target_input_args targets = {0};
+       u8 status;
+
+       if (target_0 && target_1)
+               return SDVO_CMD_STATUS_NOTSUPP;
+
+       if (target_1)
+               targets.target_1 = 1;
+
+       intel_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_INPUT, &targets,
+                            sizeof(targets));
+
+       status = intel_sdvo_read_response(output, NULL, 0);
+
+       return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+/**
+ * Return whether each input is trained.
+ *
+ * This function is making an assumption about the layout of the response,
+ * which should be checked against the docs.
+ */
+static bool intel_sdvo_get_trained_inputs(struct drm_output *output, bool *input_1, bool *input_2)
+{
+       struct intel_sdvo_get_trained_inputs_response response;
+       u8 status;
+
+       intel_sdvo_write_cmd(output, SDVO_CMD_GET_TRAINED_INPUTS, NULL, 0);
+       status = intel_sdvo_read_response(output, &response, sizeof(response));
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       *input_1 = response.input0_trained;
+       *input_2 = response.input1_trained;
+       return true;
+}
+
+static bool intel_sdvo_get_active_outputs(struct drm_output *output,
+                                         u16 *outputs)
+{
+       u8 status;
+
+       intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_OUTPUTS, NULL, 0);
+       status = intel_sdvo_read_response(output, outputs, sizeof(*outputs));
+
+       return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static bool intel_sdvo_set_active_outputs(struct drm_output *output,
+                                         u16 outputs)
+{
+       u8 status;
+
+       intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_OUTPUTS, &outputs,
+                            sizeof(outputs));
+       status = intel_sdvo_read_response(output, NULL, 0);
+       return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static bool intel_sdvo_set_encoder_power_state(struct drm_output *output,
+                                              int mode)
+{
+       u8 status, state = SDVO_ENCODER_STATE_ON;
+
+       switch (mode) {
+       case DPMSModeOn:
+               state = SDVO_ENCODER_STATE_ON;
+               break;
+       case DPMSModeStandby:
+               state = SDVO_ENCODER_STATE_STANDBY;
+               break;
+       case DPMSModeSuspend:
+               state = SDVO_ENCODER_STATE_SUSPEND;
+               break;
+       case DPMSModeOff:
+               state = SDVO_ENCODER_STATE_OFF;
+               break;
+       }
+       
+       intel_sdvo_write_cmd(output, SDVO_CMD_SET_ENCODER_POWER_STATE, &state,
+                            sizeof(state));
+       status = intel_sdvo_read_response(output, NULL, 0);
+
+       return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static bool intel_sdvo_get_input_pixel_clock_range(struct drm_output *output,
+                                                  int *clock_min,
+                                                  int *clock_max)
+{
+       struct intel_sdvo_pixel_clock_range clocks;
+       u8 status;
+
+       intel_sdvo_write_cmd(output, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE,
+                            NULL, 0);
+
+       status = intel_sdvo_read_response(output, &clocks, sizeof(clocks));
+
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       /* Convert the values from units of 10 kHz to kHz. */
+       *clock_min = clocks.min * 10;
+       *clock_max = clocks.max * 10;
+
+       return true;
+}
+
+static bool intel_sdvo_set_target_output(struct drm_output *output,
+                                        u16 outputs)
+{
+       u8 status;
+
+       intel_sdvo_write_cmd(output, SDVO_CMD_SET_TARGET_OUTPUT, &outputs,
+                            sizeof(outputs));
+
+       status = intel_sdvo_read_response(output, NULL, 0);
+       return (status == SDVO_CMD_STATUS_SUCCESS);
+}
+
+static bool intel_sdvo_get_timing(struct drm_output *output, u8 cmd,
+                                 struct intel_sdvo_dtd *dtd)
+{
+       u8 status;
+
+       intel_sdvo_write_cmd(output, cmd, NULL, 0);
+       status = intel_sdvo_read_response(output, &dtd->part1,
+                                         sizeof(dtd->part1));
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       intel_sdvo_write_cmd(output, cmd + 1, NULL, 0);
+       status = intel_sdvo_read_response(output, &dtd->part2,
+                                         sizeof(dtd->part2));
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       return true;
+}
+
+static bool intel_sdvo_get_input_timing(struct drm_output *output,
+                                        struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_get_timing(output,
+                                    SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd);
+}
+
+static bool intel_sdvo_get_output_timing(struct drm_output *output,
+                                        struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_get_timing(output,
+                                    SDVO_CMD_GET_OUTPUT_TIMINGS_PART1, dtd);
+}
+
+static bool intel_sdvo_set_timing(struct drm_output *output, u8 cmd,
+                                 struct intel_sdvo_dtd *dtd)
+{
+       u8 status;
+
+       intel_sdvo_write_cmd(output, cmd, &dtd->part1, sizeof(dtd->part1));
+       status = intel_sdvo_read_response(output, NULL, 0);
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       intel_sdvo_write_cmd(output, cmd + 1, &dtd->part2, sizeof(dtd->part2));
+       status = intel_sdvo_read_response(output, NULL, 0);
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       return true;
+}
+
+static bool intel_sdvo_set_input_timing(struct drm_output *output,
+                                        struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_set_timing(output,
+                                    SDVO_CMD_SET_INPUT_TIMINGS_PART1, dtd);
+}
+
+static bool intel_sdvo_set_output_timing(struct drm_output *output,
+                                        struct intel_sdvo_dtd *dtd)
+{
+       return intel_sdvo_set_timing(output,
+                                    SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd);
+}
+
+#if 0
+static bool intel_sdvo_get_preferred_input_timing(struct drm_output *output,
+                                                 struct intel_sdvo_dtd *dtd)
+{
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       u8 status;
+
+       intel_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1,
+                            NULL, 0);
+
+       status = intel_sdvo_read_response(output, &dtd->part1,
+                                         sizeof(dtd->part1));
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       intel_sdvo_write_cmd(output, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2,
+                            NULL, 0);
+       status = intel_sdvo_read_response(output, &dtd->part2,
+                                         sizeof(dtd->part2));
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       return true;
+}
+#endif
+
+static int intel_sdvo_get_clock_rate_mult(struct drm_output *output)
+{
+       u8 response, status;
+
+       intel_sdvo_write_cmd(output, SDVO_CMD_GET_CLOCK_RATE_MULT, NULL, 0);
+       status = intel_sdvo_read_response(output, &response, 1);
+
+       if (status != SDVO_CMD_STATUS_SUCCESS) {
+               DRM_DEBUG("Couldn't get SDVO clock rate multiplier\n");
+               return SDVO_CLOCK_RATE_MULT_1X;
+       } else {
+               DRM_DEBUG("Current clock rate multiplier: %d\n", response);
+       }
+
+       return response;
+}
+
+static bool intel_sdvo_set_clock_rate_mult(struct drm_output *output, u8 val)
+{
+       u8 status;
+
+       intel_sdvo_write_cmd(output, SDVO_CMD_SET_CLOCK_RATE_MULT, &val, 1);
+       status = intel_sdvo_read_response(output, NULL, 0);
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       return true;
+}
+
+static bool intel_sdvo_mode_fixup(struct drm_output *output,
+                                 struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode)
+{
+       /* Make the CRTC code factor in the SDVO pixel multiplier.  The SDVO
+        * device will be told of the multiplier during mode_set.
+        */
+       adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
+       return true;
+}
+
+static void intel_sdvo_mode_set(struct drm_output *output,
+                               struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = output->crtc;
+       struct intel_crtc *intel_crtc = crtc->driver_private;
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       u16 width, height;
+       u16 h_blank_len, h_sync_len, v_blank_len, v_sync_len;
+       u16 h_sync_offset, v_sync_offset;
+       u32 sdvox;
+       struct intel_sdvo_dtd output_dtd;
+       int sdvo_pixel_multiply;
+
+       if (!mode)
+               return;
+
+       width = mode->crtc_hdisplay;
+       height = mode->crtc_vdisplay;
+
+       /* do some mode translations */
+       h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start;
+       h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
+
+       v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start;
+       v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
+
+       h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start;
+       v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start;
+
+       output_dtd.part1.clock = mode->clock / 10;
+       output_dtd.part1.h_active = width & 0xff;
+       output_dtd.part1.h_blank = h_blank_len & 0xff;
+       output_dtd.part1.h_high = (((width >> 8) & 0xf) << 4) |
+               ((h_blank_len >> 8) & 0xf);
+       output_dtd.part1.v_active = height & 0xff;
+       output_dtd.part1.v_blank = v_blank_len & 0xff;
+       output_dtd.part1.v_high = (((height >> 8) & 0xf) << 4) |
+               ((v_blank_len >> 8) & 0xf);
+       
+       output_dtd.part2.h_sync_off = h_sync_offset;
+       output_dtd.part2.h_sync_width = h_sync_len & 0xff;
+       output_dtd.part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 |
+               (v_sync_len & 0xf);
+       output_dtd.part2.sync_off_width_high = ((h_sync_offset & 0x300) >> 2) |
+               ((h_sync_len & 0x300) >> 4) | ((v_sync_offset & 0x30) >> 2) |
+               ((v_sync_len & 0x30) >> 4);
+       
+       output_dtd.part2.dtd_flags = 0x18;
+       if (mode->flags & V_PHSYNC)
+               output_dtd.part2.dtd_flags |= 0x2;
+       if (mode->flags & V_PVSYNC)
+               output_dtd.part2.dtd_flags |= 0x4;
+
+       output_dtd.part2.sdvo_flags = 0;
+       output_dtd.part2.v_sync_off_high = v_sync_offset & 0xc0;
+       output_dtd.part2.reserved = 0;
+
+       /* Set the output timing to the screen */
+       intel_sdvo_set_target_output(output, sdvo_priv->active_outputs);
+       intel_sdvo_set_output_timing(output, &output_dtd);
+
+       /* Set the input timing to the screen. Assume always input 0. */
+       intel_sdvo_set_target_input(output, true, false);
+
+       /* We would like to use i830_sdvo_create_preferred_input_timing() to
+        * provide the device with a timing it can support, if it supports that
+        * feature.  However, presumably we would need to adjust the CRTC to
+        * output the preferred timing, and we don't support that currently.
+        */
+#if 0
+       success = intel_sdvo_create_preferred_input_timing(output, clock,
+                                                          width, height);
+       if (success) {
+               struct intel_sdvo_dtd *input_dtd;
+               
+               intel_sdvo_get_preferred_input_timing(output, &input_dtd);
+               intel_sdvo_set_input_timing(output, &input_dtd);
+       }
+#else
+       intel_sdvo_set_input_timing(output, &output_dtd);
+#endif 
+
+       switch (intel_sdvo_get_pixel_multiplier(mode)) {
+       case 1:
+               intel_sdvo_set_clock_rate_mult(output,
+                                              SDVO_CLOCK_RATE_MULT_1X);
+               break;
+       case 2:
+               intel_sdvo_set_clock_rate_mult(output,
+                                              SDVO_CLOCK_RATE_MULT_2X);
+               break;
+       case 4:
+               intel_sdvo_set_clock_rate_mult(output,
+                                              SDVO_CLOCK_RATE_MULT_4X);
+               break;
+       }       
+
+       /* Set the SDVO control regs. */
+        if (0/*IS_I965GM(dev)*/) {
+                sdvox = SDVO_BORDER_ENABLE;
+        } else {
+                sdvox = I915_READ(sdvo_priv->output_device);
+                switch (sdvo_priv->output_device) {
+                case SDVOB:
+                        sdvox &= SDVOB_PRESERVE_MASK;
+                        break;
+                case SDVOC:
+                        sdvox &= SDVOC_PRESERVE_MASK;
+                        break;
+                }
+                sdvox |= (9 << 19) | SDVO_BORDER_ENABLE;
+        }
+       if (intel_crtc->pipe == 1)
+               sdvox |= SDVO_PIPE_B_SELECT;
+
+       sdvo_pixel_multiply = intel_sdvo_get_pixel_multiplier(mode);
+       if (IS_I965G(dev)) {
+               /* done in crtc_mode_set as the dpll_md reg must be written 
+                  early */
+       } else if (IS_I945G(dev) || IS_I945GM(dev)) {
+               /* done in crtc_mode_set as it lives inside the 
+                  dpll register */
+       } else {
+               sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
+       }
+
+       intel_sdvo_write_sdvox(output, sdvox);
+}
+
+static void intel_sdvo_dpms(struct drm_output *output, int mode)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       u32 temp;
+
+       if (mode != DPMSModeOn) {
+               intel_sdvo_set_active_outputs(output, 0);
+               if (0)
+                       intel_sdvo_set_encoder_power_state(output, mode);
+
+               if (mode == DPMSModeOff) {
+                       temp = I915_READ(sdvo_priv->output_device);
+                       if ((temp & SDVO_ENABLE) != 0) {
+                               intel_sdvo_write_sdvox(output, temp & ~SDVO_ENABLE);
+                       }
+               }
+       } else {
+               bool input1, input2;
+               int i;
+               u8 status;
+               
+               temp = I915_READ(sdvo_priv->output_device);
+               if ((temp & SDVO_ENABLE) == 0)
+                       intel_sdvo_write_sdvox(output, temp | SDVO_ENABLE);
+               for (i = 0; i < 2; i++)
+                 intel_wait_for_vblank(dev);
+               
+               status = intel_sdvo_get_trained_inputs(output, &input1,
+                                                      &input2);
+
+               
+               /* Warn if the device reported failure to sync. 
+                * A lot of SDVO devices fail to notify of sync, but it's
+                * a given it the status is a success, we succeeded.
+                */
+               if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
+                       DRM_DEBUG("First %s output reported failure to sync\n",
+                                  SDVO_NAME(sdvo_priv));
+               }
+               
+               if (0)
+                       intel_sdvo_set_encoder_power_state(output, mode);
+               intel_sdvo_set_active_outputs(output, sdvo_priv->active_outputs);
+       }       
+       return;
+}
+
+static void intel_sdvo_save(struct drm_output *output)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       int o;
+
+       sdvo_priv->save_sdvo_mult = intel_sdvo_get_clock_rate_mult(output);
+       intel_sdvo_get_active_outputs(output, &sdvo_priv->save_active_outputs);
+
+       if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) {
+               intel_sdvo_set_target_input(output, true, false);
+               intel_sdvo_get_input_timing(output,
+                                           &sdvo_priv->save_input_dtd_1);
+       }
+
+       if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) {
+               intel_sdvo_set_target_input(output, false, true);
+               intel_sdvo_get_input_timing(output,
+                                           &sdvo_priv->save_input_dtd_2);
+       }
+
+       for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++)
+       {
+               u16  this_output = (1 << o);
+               if (sdvo_priv->caps.output_flags & this_output)
+               {
+                       intel_sdvo_set_target_output(output, this_output);
+                       intel_sdvo_get_output_timing(output,
+                                                    &sdvo_priv->save_output_dtd[o]);
+               }
+       }
+
+       sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->output_device);
+}
+
+static void intel_sdvo_restore(struct drm_output *output)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       int o;
+       int i;
+       bool input1, input2;
+       u8 status;
+
+       intel_sdvo_set_active_outputs(output, 0);
+
+       for (o = SDVO_OUTPUT_FIRST; o <= SDVO_OUTPUT_LAST; o++)
+       {
+               u16  this_output = (1 << o);
+               if (sdvo_priv->caps.output_flags & this_output) {
+                       intel_sdvo_set_target_output(output, this_output);
+                       intel_sdvo_set_output_timing(output, &sdvo_priv->save_output_dtd[o]);
+               }
+       }
+
+       if (sdvo_priv->caps.sdvo_inputs_mask & 0x1) {
+               intel_sdvo_set_target_input(output, true, false);
+               intel_sdvo_set_input_timing(output, &sdvo_priv->save_input_dtd_1);
+       }
+
+       if (sdvo_priv->caps.sdvo_inputs_mask & 0x2) {
+               intel_sdvo_set_target_input(output, false, true);
+               intel_sdvo_set_input_timing(output, &sdvo_priv->save_input_dtd_2);
+       }
+       
+       intel_sdvo_set_clock_rate_mult(output, sdvo_priv->save_sdvo_mult);
+       
+       I915_WRITE(sdvo_priv->output_device, sdvo_priv->save_SDVOX);
+       
+       if (sdvo_priv->save_SDVOX & SDVO_ENABLE)
+       {
+               for (i = 0; i < 2; i++)
+                       intel_wait_for_vblank(dev);
+               status = intel_sdvo_get_trained_inputs(output, &input1, &input2);
+               if (status == SDVO_CMD_STATUS_SUCCESS && !input1)
+                       DRM_DEBUG("First %s output reported failure to sync\n",
+                                  SDVO_NAME(sdvo_priv));
+       }
+       
+       intel_sdvo_set_active_outputs(output, sdvo_priv->save_active_outputs);
+}
+
+static int intel_sdvo_mode_valid(struct drm_output *output,
+                                struct drm_display_mode *mode)
+{
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+
+       if (mode->flags & V_DBLSCAN)
+               return MODE_NO_DBLESCAN;
+
+       if (sdvo_priv->pixel_clock_min > mode->clock)
+               return MODE_CLOCK_LOW;
+
+       if (sdvo_priv->pixel_clock_max < mode->clock)
+               return MODE_CLOCK_HIGH;
+
+       return MODE_OK;
+}
+
+static bool intel_sdvo_get_capabilities(struct drm_output *output, struct intel_sdvo_caps *caps)
+{
+       u8 status;
+
+       intel_sdvo_write_cmd(output, SDVO_CMD_GET_DEVICE_CAPS, NULL, 0);
+       status = intel_sdvo_read_response(output, caps, sizeof(*caps));
+       if (status != SDVO_CMD_STATUS_SUCCESS)
+               return false;
+
+       return true;
+}
+
+
+static void intel_sdvo_dump_cmd(struct drm_output *output, int opcode)
+{
+
+
+}
+
+static void intel_sdvo_dump_device(struct drm_output *output)
+{
+
+}
+
+void intel_sdvo_dump(void)
+{
+
+}
+
+struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB)
+{
+       struct drm_output *output = 0;
+       struct intel_output *iout = 0;
+       struct intel_sdvo_priv *sdvo;
+
+       /* find the sdvo output */
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+               iout = output->driver_private;
+
+               if (iout->type != INTEL_OUTPUT_SDVO)
+                       continue;
+
+               sdvo = iout->dev_priv;
+
+               if (sdvo->output_device == SDVOB && sdvoB)
+                       return output;
+
+               if (sdvo->output_device == SDVOC && !sdvoB)
+                       return output;
+
+    }
+
+       return 0;
+}
+
+int intel_sdvo_supports_hotplug(struct drm_output *output)
+{
+       u8 response[2];
+       u8 status;
+       DRM_DEBUG("\n");
+
+       if (!output)
+               return 0;
+
+       intel_sdvo_write_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0);
+       status = intel_sdvo_read_response(output, &response, 2);
+
+       if (response[0] !=0)
+               return 1;
+
+       return 0;
+}
+
+void intel_sdvo_set_hotplug(struct drm_output *output, int on)
+{
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+       u8 response[2];
+       u8 status;
+
+       intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
+       intel_sdvo_read_response(output, &response, 2);
+
+       if (on) {
+               sdvo_priv->hotplug_enabled = 1;
+
+               intel_sdvo_write_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0);
+               status = intel_sdvo_read_response(output, &response, 2);
+
+               intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
+       } else {
+               sdvo_priv->hotplug_enabled = 0;
+
+               response[0] = 0;
+               response[1] = 0;
+               intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2);
+       }
+
+       intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0);
+       intel_sdvo_read_response(output, &response, 2);
+}
+
+static enum drm_output_status intel_sdvo_detect(struct drm_output *output)
+{
+       u8 response[2];
+       u8 status;
+
+       intel_sdvo_write_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
+       status = intel_sdvo_read_response(output, &response, 2);
+
+       DRM_DEBUG("SDVO response %d %d\n", response[0], response[1]);
+       if ((response[0] != 0) || (response[1] != 0))
+               return output_status_connected;
+       else
+               return output_status_disconnected;
+}
+
+static int intel_sdvo_get_modes(struct drm_output *output)
+{
+       /* set the bus switch and get the modes */
+       intel_sdvo_set_control_bus_switch(output, SDVO_CONTROL_BUS_DDC2);
+       intel_ddc_get_modes(output);
+
+       if (list_empty(&output->probed_modes))
+               return 0;
+       return 1;
+#if 0
+       /* Mac mini hack.  On this device, I get DDC through the analog, which
+        * load-detects as disconnected.  I fail to DDC through the SDVO DDC,
+        * but it does load-detect as connected.  So, just steal the DDC bits 
+        * from analog when we fail at finding it the right way.
+        */
+       /* TODO */
+       return NULL;
+
+       return NULL;
+#endif
+}
+
+static void intel_sdvo_destroy(struct drm_output *output)
+{
+       struct intel_output *intel_output = output->driver_private;
+
+       if (intel_output->i2c_bus)
+               intel_i2c_destroy(intel_output->i2c_bus);
+
+       if (intel_output) {
+               kfree(intel_output);
+               output->driver_private = NULL;
+       }
+}
+
+static const struct drm_output_funcs intel_sdvo_output_funcs = {
+       .dpms = intel_sdvo_dpms,
+       .save = intel_sdvo_save,
+       .restore = intel_sdvo_restore,
+       .mode_valid = intel_sdvo_mode_valid,
+       .mode_fixup = intel_sdvo_mode_fixup,
+       .prepare = intel_output_prepare,
+       .mode_set = intel_sdvo_mode_set,
+       .commit = intel_output_commit,
+       .detect = intel_sdvo_detect,
+       .get_modes = intel_sdvo_get_modes,
+       .cleanup = intel_sdvo_destroy
+};
+
+void intel_sdvo_init(struct drm_device *dev, int output_device)
+{
+       struct drm_output *output;
+       struct intel_output *intel_output;
+       struct intel_sdvo_priv *sdvo_priv;
+       struct intel_i2c_chan *i2cbus = NULL;
+       int connector_type;
+       u8 ch[0x40];
+       int i;
+       int output_type, output_id;
+
+       output = drm_output_create(dev, &intel_sdvo_output_funcs,
+                                  DRM_MODE_OUTPUT_NONE);
+       if (!output)
+               return;
+
+       intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
+       if (!intel_output) {
+               drm_output_destroy(output);
+               return;
+       }
+
+       sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1);
+       intel_output->type = INTEL_OUTPUT_SDVO;
+       output->driver_private = intel_output;
+       output->interlace_allowed = 0;
+       output->doublescan_allowed = 0;
+
+       /* setup the DDC bus. */
+       if (output_device == SDVOB)
+               i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB");
+       else
+               i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC");
+
+       if (i2cbus == NULL) {
+               drm_output_destroy(output);
+               return;
+       }
+
+       sdvo_priv->i2c_bus = i2cbus;
+
+       if (output_device == SDVOB) {
+               output_id = 1;
+               sdvo_priv->i2c_bus->slave_addr = 0x38;
+       } else {
+               output_id = 2;
+               sdvo_priv->i2c_bus->slave_addr = 0x39;
+       }
+
+       sdvo_priv->output_device = output_device;
+       sdvo_priv->hotplug_enabled = 0;
+       intel_output->i2c_bus = i2cbus;
+       intel_output->dev_priv = sdvo_priv;
+
+
+       /* Read the regs to test if we can talk to the device */
+       for (i = 0; i < 0x40; i++) {
+               if (!intel_sdvo_read_byte(output, i, &ch[i])) {
+                       DRM_DEBUG("No SDVO device found on SDVO%c\n",
+                                 output_device == SDVOB ? 'B' : 'C');
+                       drm_output_destroy(output);
+                       return;
+               }
+       }
+
+       intel_sdvo_get_capabilities(output, &sdvo_priv->caps);
+
+       memset(&sdvo_priv->active_outputs, 0, sizeof(sdvo_priv->active_outputs));
+
+       /* TODO, CVBS, SVID, YPRPB & SCART outputs. */
+       if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0)
+       {
+               sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0;
+               output->subpixel_order = SubPixelHorizontalRGB;
+               output_type = DRM_MODE_OUTPUT_DAC;
+               connector_type = ConnectorVGA;
+       }
+       else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1)
+       {
+               sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1;
+               output->subpixel_order = SubPixelHorizontalRGB;
+               output_type = DRM_MODE_OUTPUT_DAC;
+               connector_type = ConnectorVGA;
+       }
+       else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
+       {
+               sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0;
+               output->subpixel_order = SubPixelHorizontalRGB;
+               output_type = DRM_MODE_OUTPUT_TMDS;
+               connector_type = ConnectorDVID;
+       }
+       else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS1)
+       {
+               sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS1;
+               output->subpixel_order = SubPixelHorizontalRGB;
+               output_type = DRM_MODE_OUTPUT_TMDS;
+               connector_type = ConnectorDVID;
+       }
+       else
+       {
+               unsigned char bytes[2];
+               
+               memcpy (bytes, &sdvo_priv->caps.output_flags, 2);
+               DRM_DEBUG("%s: No active RGB or TMDS outputs (0x%02x%02x)\n",
+                         SDVO_NAME(sdvo_priv),
+                         bytes[0], bytes[1]);
+               drm_output_destroy(output);
+               return;
+       }
+       
+       output->output_type = output_type;
+       output->output_type_id = output_id;
+
+       /* Set the input timing to the screen. Assume always input 0. */
+       intel_sdvo_set_target_input(output, true, false);
+       
+       intel_sdvo_get_input_pixel_clock_range(output,
+                                              &sdvo_priv->pixel_clock_min,
+                                              &sdvo_priv->pixel_clock_max);
+
+
+       DRM_DEBUG("%s device VID/DID: %02X:%02X.%02X, "
+                 "clock range %dMHz - %dMHz, "
+                 "input 1: %c, input 2: %c, "
+                 "output 1: %c, output 2: %c\n",
+                 SDVO_NAME(sdvo_priv),
+                 sdvo_priv->caps.vendor_id, sdvo_priv->caps.device_id,
+                 sdvo_priv->caps.device_rev_id,
+                 sdvo_priv->pixel_clock_min / 1000,
+                 sdvo_priv->pixel_clock_max / 1000,
+                 (sdvo_priv->caps.sdvo_inputs_mask & 0x1) ? 'Y' : 'N',
+                 (sdvo_priv->caps.sdvo_inputs_mask & 0x2) ? 'Y' : 'N',
+                 /* check currently supported outputs */
+                 sdvo_priv->caps.output_flags & 
+                       (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_RGB0) ? 'Y' : 'N',
+                 sdvo_priv->caps.output_flags & 
+                       (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
+
+       intel_output->ddc_bus = i2cbus; 
+
+       drm_output_attach_property(output, dev->mode_config.connector_type_property, connector_type);
+}
diff --git a/linux-core/intel_sdvo_regs.h b/linux-core/intel_sdvo_regs.h
new file mode 100644 (file)
index 0000000..a9d1671
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Copyright Â© 2006-2007 Intel Corporation
+ *
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ */
+
+/**
+ * @file SDVO command definitions and structures.
+ */
+
+#define SDVO_OUTPUT_FIRST   (0)
+#define SDVO_OUTPUT_TMDS0   (1 << 0)
+#define SDVO_OUTPUT_RGB0    (1 << 1)
+#define SDVO_OUTPUT_CVBS0   (1 << 2)
+#define SDVO_OUTPUT_SVID0   (1 << 3)
+#define SDVO_OUTPUT_YPRPB0  (1 << 4)
+#define SDVO_OUTPUT_SCART0  (1 << 5)
+#define SDVO_OUTPUT_LVDS0   (1 << 6)
+#define SDVO_OUTPUT_TMDS1   (1 << 8)
+#define SDVO_OUTPUT_RGB1    (1 << 9)
+#define SDVO_OUTPUT_CVBS1   (1 << 10)
+#define SDVO_OUTPUT_SVID1   (1 << 11)
+#define SDVO_OUTPUT_YPRPB1  (1 << 12)
+#define SDVO_OUTPUT_SCART1  (1 << 13)
+#define SDVO_OUTPUT_LVDS1   (1 << 14)
+#define SDVO_OUTPUT_LAST    (14)
+
+struct intel_sdvo_caps {
+    u8 vendor_id;
+    u8 device_id;
+    u8 device_rev_id;
+    u8 sdvo_version_major;
+    u8 sdvo_version_minor;
+    unsigned int sdvo_inputs_mask:2;
+    unsigned int smooth_scaling:1;
+    unsigned int sharp_scaling:1;
+    unsigned int up_scaling:1;
+    unsigned int down_scaling:1;
+    unsigned int stall_support:1;
+    unsigned int pad:1;
+    u16 output_flags;
+} __attribute__((packed));
+
+/** This matches the EDID DTD structure, more or less */
+struct intel_sdvo_dtd {
+    struct {
+       u16 clock;              /**< pixel clock, in 10kHz units */
+       u8 h_active;            /**< lower 8 bits (pixels) */
+       u8 h_blank;             /**< lower 8 bits (pixels) */
+       u8 h_high;              /**< upper 4 bits each h_active, h_blank */
+       u8 v_active;            /**< lower 8 bits (lines) */
+       u8 v_blank;             /**< lower 8 bits (lines) */
+       u8 v_high;              /**< upper 4 bits each v_active, v_blank */
+    } part1;
+
+    struct {
+       u8 h_sync_off;  /**< lower 8 bits, from hblank start */
+       u8 h_sync_width;        /**< lower 8 bits (pixels) */
+       /** lower 4 bits each vsync offset, vsync width */
+       u8 v_sync_off_width;
+       /**
+        * 2 high bits of hsync offset, 2 high bits of hsync width,
+        * bits 4-5 of vsync offset, and 2 high bits of vsync width.
+        */
+       u8 sync_off_width_high;
+       u8 dtd_flags;
+       u8 sdvo_flags;
+       /** bits 6-7 of vsync offset at bits 6-7 */
+       u8 v_sync_off_high;
+       u8 reserved;
+    } part2;
+} __attribute__((packed));
+
+struct intel_sdvo_pixel_clock_range {
+    u16 min;                   /**< pixel clock, in 10kHz units */
+    u16 max;                   /**< pixel clock, in 10kHz units */
+} __attribute__((packed));
+
+struct intel_sdvo_preferred_input_timing_args {
+    u16 clock;
+    u16 width;
+    u16 height;
+} __attribute__((packed));
+
+/* I2C registers for SDVO */
+#define SDVO_I2C_ARG_0                         0x07
+#define SDVO_I2C_ARG_1                         0x06
+#define SDVO_I2C_ARG_2                         0x05
+#define SDVO_I2C_ARG_3                         0x04
+#define SDVO_I2C_ARG_4                         0x03
+#define SDVO_I2C_ARG_5                         0x02
+#define SDVO_I2C_ARG_6                         0x01
+#define SDVO_I2C_ARG_7                         0x00
+#define SDVO_I2C_OPCODE                                0x08
+#define SDVO_I2C_CMD_STATUS                    0x09
+#define SDVO_I2C_RETURN_0                      0x0a
+#define SDVO_I2C_RETURN_1                      0x0b
+#define SDVO_I2C_RETURN_2                      0x0c
+#define SDVO_I2C_RETURN_3                      0x0d
+#define SDVO_I2C_RETURN_4                      0x0e
+#define SDVO_I2C_RETURN_5                      0x0f
+#define SDVO_I2C_RETURN_6                      0x10
+#define SDVO_I2C_RETURN_7                      0x11
+#define SDVO_I2C_VENDOR_BEGIN                  0x20
+
+/* Status results */
+#define SDVO_CMD_STATUS_POWER_ON               0x0
+#define SDVO_CMD_STATUS_SUCCESS                        0x1
+#define SDVO_CMD_STATUS_NOTSUPP                        0x2
+#define SDVO_CMD_STATUS_INVALID_ARG            0x3
+#define SDVO_CMD_STATUS_PENDING                        0x4
+#define SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED   0x5
+#define SDVO_CMD_STATUS_SCALING_NOT_SUPP       0x6
+
+/* SDVO commands, argument/result registers */
+
+#define SDVO_CMD_RESET                                 0x01
+
+/** Returns a struct intel_sdvo_caps */
+#define SDVO_CMD_GET_DEVICE_CAPS                       0x02
+
+#define SDVO_CMD_GET_FIRMWARE_REV                      0x86
+# define SDVO_DEVICE_FIRMWARE_MINOR                    SDVO_I2C_RETURN_0
+# define SDVO_DEVICE_FIRMWARE_MAJOR                    SDVO_I2C_RETURN_1
+# define SDVO_DEVICE_FIRMWARE_PATCH                    SDVO_I2C_RETURN_2
+
+/**
+ * Reports which inputs are trained (managed to sync).
+ *
+ * Devices must have trained within 2 vsyncs of a mode change.
+ */
+#define SDVO_CMD_GET_TRAINED_INPUTS                    0x03
+struct intel_sdvo_get_trained_inputs_response {
+    unsigned int input0_trained:1;
+    unsigned int input1_trained:1;
+    unsigned int pad:6;
+} __attribute__((packed));
+
+/** Returns a struct intel_sdvo_output_flags of active outputs. */
+#define SDVO_CMD_GET_ACTIVE_OUTPUTS                    0x04
+
+/**
+ * Sets the current set of active outputs.
+ *
+ * Takes a struct intel_sdvo_output_flags.  Must be preceded by a SET_IN_OUT_MAP
+ * on multi-output devices.
+ */
+#define SDVO_CMD_SET_ACTIVE_OUTPUTS                    0x05
+
+/**
+ * Returns the current mapping of SDVO inputs to outputs on the device.
+ *
+ * Returns two struct intel_sdvo_output_flags structures.
+ */
+#define SDVO_CMD_GET_IN_OUT_MAP                                0x06
+
+/**
+ * Sets the current mapping of SDVO inputs to outputs on the device.
+ *
+ * Takes two struct i380_sdvo_output_flags structures.
+ */
+#define SDVO_CMD_SET_IN_OUT_MAP                                0x07
+
+/**
+ * Returns a struct intel_sdvo_output_flags of attached displays.
+ */
+#define SDVO_CMD_GET_ATTACHED_DISPLAYS                 0x0b
+
+/**
+ * Returns a struct intel_sdvo_ouptut_flags of displays supporting hot plugging.
+ */
+#define SDVO_CMD_GET_HOT_PLUG_SUPPORT                  0x0c
+
+/**
+ * Takes a struct intel_sdvo_output_flags.
+ */
+#define SDVO_CMD_SET_ACTIVE_HOT_PLUG                   0x0d
+
+/**
+ * Returns a struct intel_sdvo_output_flags of displays with hot plug
+ * interrupts enabled.
+ */
+#define SDVO_CMD_GET_ACTIVE_HOT_PLUG                   0x0e
+
+#define SDVO_CMD_GET_INTERRUPT_EVENT_SOURCE            0x0f
+struct intel_sdvo_get_interrupt_event_source_response {
+    u16 interrupt_status;
+    unsigned int ambient_light_interrupt:1;
+    unsigned int pad:7;
+} __attribute__((packed));
+
+/**
+ * Selects which input is affected by future input commands.
+ *
+ * Commands affected include SET_INPUT_TIMINGS_PART[12],
+ * GET_INPUT_TIMINGS_PART[12], GET_PREFERRED_INPUT_TIMINGS_PART[12],
+ * GET_INPUT_PIXEL_CLOCK_RANGE, and CREATE_PREFERRED_INPUT_TIMINGS.
+ */
+#define SDVO_CMD_SET_TARGET_INPUT                      0x10
+struct intel_sdvo_set_target_input_args {
+    unsigned int target_1:1;
+    unsigned int pad:7;
+} __attribute__((packed));
+
+/**
+ * Takes a struct intel_sdvo_output_flags of which outputs are targetted by
+ * future output commands.
+ *
+ * Affected commands inclue SET_OUTPUT_TIMINGS_PART[12],
+ * GET_OUTPUT_TIMINGS_PART[12], and GET_OUTPUT_PIXEL_CLOCK_RANGE.
+ */
+#define SDVO_CMD_SET_TARGET_OUTPUT                     0x11
+
+#define SDVO_CMD_GET_INPUT_TIMINGS_PART1               0x12
+#define SDVO_CMD_GET_INPUT_TIMINGS_PART2               0x13
+#define SDVO_CMD_SET_INPUT_TIMINGS_PART1               0x14
+#define SDVO_CMD_SET_INPUT_TIMINGS_PART2               0x15
+#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART1              0x16
+#define SDVO_CMD_SET_OUTPUT_TIMINGS_PART2              0x17
+#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART1              0x18
+#define SDVO_CMD_GET_OUTPUT_TIMINGS_PART2              0x19
+/* Part 1 */
+# define SDVO_DTD_CLOCK_LOW                            SDVO_I2C_ARG_0
+# define SDVO_DTD_CLOCK_HIGH                           SDVO_I2C_ARG_1
+# define SDVO_DTD_H_ACTIVE                             SDVO_I2C_ARG_2
+# define SDVO_DTD_H_BLANK                              SDVO_I2C_ARG_3
+# define SDVO_DTD_H_HIGH                               SDVO_I2C_ARG_4
+# define SDVO_DTD_V_ACTIVE                             SDVO_I2C_ARG_5
+# define SDVO_DTD_V_BLANK                              SDVO_I2C_ARG_6
+# define SDVO_DTD_V_HIGH                               SDVO_I2C_ARG_7
+/* Part 2 */
+# define SDVO_DTD_HSYNC_OFF                            SDVO_I2C_ARG_0
+# define SDVO_DTD_HSYNC_WIDTH                          SDVO_I2C_ARG_1
+# define SDVO_DTD_VSYNC_OFF_WIDTH                      SDVO_I2C_ARG_2
+# define SDVO_DTD_SYNC_OFF_WIDTH_HIGH                  SDVO_I2C_ARG_3
+# define SDVO_DTD_DTD_FLAGS                            SDVO_I2C_ARG_4
+# define SDVO_DTD_DTD_FLAG_INTERLACED                          (1 << 7)
+# define SDVO_DTD_DTD_FLAG_STEREO_MASK                         (3 << 5)
+# define SDVO_DTD_DTD_FLAG_INPUT_MASK                          (3 << 3)
+# define SDVO_DTD_DTD_FLAG_SYNC_MASK                           (3 << 1)
+# define SDVO_DTD_SDVO_FLAS                            SDVO_I2C_ARG_5
+# define SDVO_DTD_SDVO_FLAG_STALL                              (1 << 7)
+# define SDVO_DTD_SDVO_FLAG_CENTERED                           (0 << 6)
+# define SDVO_DTD_SDVO_FLAG_UPPER_LEFT                         (1 << 6)
+# define SDVO_DTD_SDVO_FLAG_SCALING_MASK                       (3 << 4)
+# define SDVO_DTD_SDVO_FLAG_SCALING_NONE                       (0 << 4)
+# define SDVO_DTD_SDVO_FLAG_SCALING_SHARP                      (1 << 4)
+# define SDVO_DTD_SDVO_FLAG_SCALING_SMOOTH                     (2 << 4)
+# define SDVO_DTD_VSYNC_OFF_HIGH                       SDVO_I2C_ARG_6
+
+/**
+ * Generates a DTD based on the given width, height, and flags.
+ *
+ * This will be supported by any device supporting scaling or interlaced
+ * modes.
+ */
+#define SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING         0x1a
+# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_LOW         SDVO_I2C_ARG_0
+# define SDVO_PREFERRED_INPUT_TIMING_CLOCK_HIGH                SDVO_I2C_ARG_1
+# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_LOW         SDVO_I2C_ARG_2
+# define SDVO_PREFERRED_INPUT_TIMING_WIDTH_HIGH                SDVO_I2C_ARG_3
+# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_LOW                SDVO_I2C_ARG_4
+# define SDVO_PREFERRED_INPUT_TIMING_HEIGHT_HIGH       SDVO_I2C_ARG_5
+# define SDVO_PREFERRED_INPUT_TIMING_FLAGS             SDVO_I2C_ARG_6
+# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_INTERLACED          (1 << 0)
+# define SDVO_PREFERRED_INPUT_TIMING_FLAGS_SCALED              (1 << 1)
+
+#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1      0x1b
+#define SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2      0x1c
+
+/** Returns a struct intel_sdvo_pixel_clock_range */
+#define SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE           0x1d
+/** Returns a struct intel_sdvo_pixel_clock_range */
+#define SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE          0x1e
+
+/** Returns a byte bitfield containing SDVO_CLOCK_RATE_MULT_* flags */
+#define SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS                0x1f
+
+/** Returns a byte containing a SDVO_CLOCK_RATE_MULT_* flag */
+#define SDVO_CMD_GET_CLOCK_RATE_MULT                   0x20
+/** Takes a byte containing a SDVO_CLOCK_RATE_MULT_* flag */
+#define SDVO_CMD_SET_CLOCK_RATE_MULT                   0x21
+# define SDVO_CLOCK_RATE_MULT_1X                               (1 << 0)
+# define SDVO_CLOCK_RATE_MULT_2X                               (1 << 1)
+# define SDVO_CLOCK_RATE_MULT_4X                               (1 << 3)
+
+#define SDVO_CMD_GET_SUPPORTED_TV_FORMATS              0x27
+
+#define SDVO_CMD_GET_TV_FORMAT                         0x28
+
+#define SDVO_CMD_SET_TV_FORMAT                         0x29
+
+#define SDVO_CMD_GET_SUPPORTED_POWER_STATES            0x2a
+#define SDVO_CMD_GET_ENCODER_POWER_STATE               0x2b
+#define SDVO_CMD_SET_ENCODER_POWER_STATE               0x2c
+# define SDVO_ENCODER_STATE_ON                                 (1 << 0)
+# define SDVO_ENCODER_STATE_STANDBY                            (1 << 1)
+# define SDVO_ENCODER_STATE_SUSPEND                            (1 << 2)
+# define SDVO_ENCODER_STATE_OFF                                        (1 << 3)
+
+#define SDVO_CMD_SET_TV_RESOLUTION_SUPPORT             0x93
+
+#define SDVO_CMD_SET_CONTROL_BUS_SWITCH                        0x7a
+# define SDVO_CONTROL_BUS_PROM                         0x0
+# define SDVO_CONTROL_BUS_DDC1                         0x1
+# define SDVO_CONTROL_BUS_DDC2                         0x2
+# define SDVO_CONTROL_BUS_DDC3                         0x3
+
diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c
new file mode 100644 (file)
index 0000000..0edbdba
--- /dev/null
@@ -0,0 +1,1763 @@
+/*
+ * Copyright Â© 2006 Intel Corporation
+ *
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ *    Eric Anholt <eric@anholt.net>
+ *
+ */
+
+/** @file
+ * Integrated TV-out support for the 915GM and 945GM.
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "drm_edid.h"
+#include "intel_drv.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+enum tv_type {
+       TV_TYPE_NONE,
+       TV_TYPE_UNKNOWN,
+       TV_TYPE_COMPOSITE,
+       TV_TYPE_SVIDEO,
+       TV_TYPE_COMPONENT
+};
+
+enum tv_margin {
+       TV_MARGIN_LEFT, TV_MARGIN_TOP,
+       TV_MARGIN_RIGHT, TV_MARGIN_BOTTOM
+};
+
+/** Private structure for the integrated TV support */
+struct intel_tv_priv {
+       int type;
+       char *tv_format;
+       int margin[4];
+       u32 save_TV_H_CTL_1;
+       u32 save_TV_H_CTL_2;
+       u32 save_TV_H_CTL_3;
+       u32 save_TV_V_CTL_1;
+       u32 save_TV_V_CTL_2;
+       u32 save_TV_V_CTL_3;
+       u32 save_TV_V_CTL_4;
+       u32 save_TV_V_CTL_5;
+       u32 save_TV_V_CTL_6;
+       u32 save_TV_V_CTL_7;
+       u32 save_TV_SC_CTL_1, save_TV_SC_CTL_2, save_TV_SC_CTL_3;
+
+       u32 save_TV_CSC_Y;
+       u32 save_TV_CSC_Y2;
+       u32 save_TV_CSC_U;
+       u32 save_TV_CSC_U2;
+       u32 save_TV_CSC_V;
+       u32 save_TV_CSC_V2;
+       u32 save_TV_CLR_KNOBS;
+       u32 save_TV_CLR_LEVEL;
+       u32 save_TV_WIN_POS;
+       u32 save_TV_WIN_SIZE;
+       u32 save_TV_FILTER_CTL_1;
+       u32 save_TV_FILTER_CTL_2;
+       u32 save_TV_FILTER_CTL_3;
+
+       u32 save_TV_H_LUMA[60];
+       u32 save_TV_H_CHROMA[60];
+       u32 save_TV_V_LUMA[43];
+       u32 save_TV_V_CHROMA[43];
+
+       u32 save_TV_DAC;
+       u32 save_TV_CTL;
+};
+
+struct video_levels {
+       int blank, black, burst;
+};
+
+struct color_conversion {
+       u16 ry, gy, by, ay;
+       u16 ru, gu, bu, au;
+       u16 rv, gv, bv, av;
+};
+
+static const u32 filter_table[] = {
+       0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
+       0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
+       0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
+       0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
+       0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
+       0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
+       0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
+       0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
+       0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
+       0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
+       0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
+       0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
+       0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
+       0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
+       0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
+       0xB1403000, 0x2E203500, 0x35002E20, 0x3000B140,
+       0x35A0B160, 0x2DC02E80, 0xB1403480, 0xB1603000,
+       0x2EA03640, 0x34002D80, 0x3000B120, 0x36E0B160,
+       0x2D202EF0, 0xB1203380, 0xB1603000, 0x2F303780,
+       0x33002CC0, 0x3000B100, 0x3820B160, 0x2C802F50,
+       0xB10032A0, 0xB1603000, 0x2F9038C0, 0x32202C20,
+       0x3000B0E0, 0x3980B160, 0x2BC02FC0, 0xB0E031C0,
+       0xB1603000, 0x2FF03A20, 0x31602B60, 0xB020B0C0,
+       0x3AE0B160, 0x2B001810, 0xB0C03120, 0xB140B020,
+       0x18283BA0, 0x30C02A80, 0xB020B0A0, 0x3C60B140,
+       0x2A201838, 0xB0A03080, 0xB120B020, 0x18383D20,
+       0x304029C0, 0xB040B080, 0x3DE0B100, 0x29601848,
+       0xB0803000, 0xB100B040, 0x18483EC0, 0xB0402900,
+       0xB040B060, 0x3F80B0C0, 0x28801858, 0xB060B080,
+       0xB0A0B060, 0x18602820, 0xB0A02820, 0x0000B060,
+       0x36403000, 0x2D002CC0, 0x30003640, 0x2D0036C0,
+       0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
+       0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
+       0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
+       0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
+       0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
+       0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
+       0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
+       0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
+       0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
+       0x28003100, 0x28002F00, 0x00003100, 0x36403000, 
+       0x2D002CC0, 0x30003640, 0x2D0036C0,
+       0x35C02CC0, 0x37403000, 0x2C802D40, 0x30003540,
+       0x2D8037C0, 0x34C02C40, 0x38403000, 0x2BC02E00,
+       0x30003440, 0x2E2038C0, 0x34002B80, 0x39803000,
+       0x2B402E40, 0x30003380, 0x2E603A00, 0x33402B00,
+       0x3A803040, 0x2A802EA0, 0x30403300, 0x2EC03B40,
+       0x32802A40, 0x3C003040, 0x2A002EC0, 0x30803240,
+       0x2EC03C80, 0x320029C0, 0x3D403080, 0x29402F00,
+       0x308031C0, 0x2F203DC0, 0x31802900, 0x3E8030C0,
+       0x28802F40, 0x30C03140, 0x2F203F40, 0x31402840,
+       0x28003100, 0x28002F00, 0x00003100,
+};
+
+/*
+ * Color conversion values have 3 separate fixed point formats:
+ *
+ * 10 bit fields (ay, au)
+ *   1.9 fixed point (b.bbbbbbbbb)
+ * 11 bit fields (ry, by, ru, gu, gv)
+ *   exp.mantissa (ee.mmmmmmmmm)
+ *   ee = 00 = 10^-1 (0.mmmmmmmmm)
+ *   ee = 01 = 10^-2 (0.0mmmmmmmmm)
+ *   ee = 10 = 10^-3 (0.00mmmmmmmmm)
+ *   ee = 11 = 10^-4 (0.000mmmmmmmmm)
+ * 12 bit fields (gy, rv, bu)
+ *   exp.mantissa (eee.mmmmmmmmm)
+ *   eee = 000 = 10^-1 (0.mmmmmmmmm)
+ *   eee = 001 = 10^-2 (0.0mmmmmmmmm)
+ *   eee = 010 = 10^-3 (0.00mmmmmmmmm)
+ *   eee = 011 = 10^-4 (0.000mmmmmmmmm)
+ *   eee = 100 = reserved
+ *   eee = 101 = reserved
+ *   eee = 110 = reserved
+ *   eee = 111 = 10^0 (m.mmmmmmmm) (only usable for 1.0 representation)
+ *
+ * Saturation and contrast are 8 bits, with their own representation:
+ * 8 bit field (saturation, contrast)
+ *   exp.mantissa (ee.mmmmmm)
+ *   ee = 00 = 10^-1 (0.mmmmmm)
+ *   ee = 01 = 10^0 (m.mmmmm)
+ *   ee = 10 = 10^1 (mm.mmmm)
+ *   ee = 11 = 10^2 (mmm.mmm)
+ *
+ * Simple conversion function:
+ *
+ * static u32
+ * float_to_csc_11(float f)
+ * {
+ *     u32 exp;
+ *     u32 mant;
+ *     u32 ret;
+ * 
+ *     if (f < 0)
+ *         f = -f;
+ * 
+ *     if (f >= 1) {
+ *         exp = 0x7;
+ *        mant = 1 << 8;
+ *     } else {
+ *         for (exp = 0; exp < 3 && f < 0.5; exp++)
+ *            f *= 2.0;
+ *         mant = (f * (1 << 9) + 0.5);
+ *         if (mant >= (1 << 9))
+ *             mant = (1 << 9) - 1;
+ *     }
+ *     ret = (exp << 9) | mant;
+ *     return ret;
+ * }
+ */
+
+/*
+ * Behold, magic numbers!  If we plant them they might grow a big
+ * s-video cable to the sky... or something.
+ *
+ * Pre-converted to appropriate hex value.
+ */
+
+/*
+ * PAL & NTSC values for composite & s-video connections
+ */
+static const struct color_conversion ntsc_m_csc_composite = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
+       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
+       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
+};
+
+static const struct video_levels ntsc_m_levels_composite = {
+       .blank = 225, .black = 267, .burst = 113,
+};
+
+static const struct color_conversion ntsc_m_csc_svideo = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
+       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
+       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
+};
+
+static const struct video_levels ntsc_m_levels_svideo = {
+       .blank = 266, .black = 316, .burst = 133,
+};
+
+static const struct color_conversion ntsc_j_csc_composite = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0119,
+       .ru = 0x074c, .gu = 0x0546, .bu = 0x05ec, .au = 0x0f00,
+       .rv = 0x035a, .gv = 0x0322, .bv = 0x06e1, .av = 0x0f00,
+};
+
+static const struct video_levels ntsc_j_levels_composite = {
+       .blank = 225, .black = 225, .burst = 113,
+};
+
+static const struct color_conversion ntsc_j_csc_svideo = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x014c,
+       .ru = 0x0788, .gu = 0x0581, .bu = 0x0322, .au = 0x0f00,
+       .rv = 0x0399, .gv = 0x0356, .bv = 0x070a, .av = 0x0f00,
+};
+
+static const struct video_levels ntsc_j_levels_svideo = {
+       .blank = 266, .black = 266, .burst = 133,
+};
+
+static const struct color_conversion pal_csc_composite = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0113,
+       .ru = 0x0745, .gu = 0x053f, .bu = 0x05e1, .au = 0x0f00,
+       .rv = 0x0353, .gv = 0x031c, .bv = 0x06dc, .av = 0x0f00,
+};
+       
+static const struct video_levels pal_levels_composite = {
+       .blank = 237, .black = 237, .burst = 118,
+};
+
+static const struct color_conversion pal_csc_svideo = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0145,
+       .ru = 0x0780, .gu = 0x0579, .bu = 0x031c, .au = 0x0f00,
+       .rv = 0x0390, .gv = 0x034f, .bv = 0x0705, .av = 0x0f00,
+};
+
+static const struct video_levels pal_levels_svideo = {
+       .blank = 280, .black = 280, .burst = 139,
+};
+
+static const struct color_conversion pal_m_csc_composite = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
+       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
+       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
+};
+
+static const struct video_levels pal_m_levels_composite = {
+       .blank = 225, .black = 267, .burst = 113,
+};
+
+static const struct color_conversion pal_m_csc_svideo = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
+       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
+       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
+};
+
+static const struct video_levels pal_m_levels_svideo = {
+       .blank = 266, .black = 316, .burst = 133,
+};
+
+static const struct color_conversion pal_n_csc_composite = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0104,
+       .ru = 0x0733, .gu = 0x052d, .bu = 0x05c7, .au = 0x0f00,
+       .rv = 0x0340, .gv = 0x030c, .bv = 0x06d0, .av = 0x0f00,
+};
+
+static const struct video_levels pal_n_levels_composite = {
+       .blank = 225, .black = 267, .burst = 118,
+};
+
+static const struct color_conversion pal_n_csc_svideo = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0134,
+       .ru = 0x076a, .gu = 0x0564, .bu = 0x030d, .au = 0x0f00,
+       .rv = 0x037a, .gv = 0x033d, .bv = 0x06f6, .av = 0x0f00,
+};
+
+static const struct video_levels pal_n_levels_svideo = {
+       .blank = 266, .black = 316, .burst = 139,
+};
+
+/*
+ * Component connections
+ */
+static const struct color_conversion sdtv_csc_yprpb = {
+       .ry = 0x0332, .gy = 0x012d, .by = 0x07d3, .ay = 0x0146,
+       .ru = 0x0559, .gu = 0x0353, .bu = 0x0100, .au = 0x0f00,
+       .rv = 0x0100, .gv = 0x03ad, .bv = 0x074d, .av = 0x0f00,
+};
+
+static const struct color_conversion sdtv_csc_rgb = {
+       .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166,
+       .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166,
+       .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166,
+};
+
+static const struct color_conversion hdtv_csc_yprpb = {
+       .ry = 0x05b3, .gy = 0x016e, .by = 0x0728, .ay = 0x0146,
+       .ru = 0x07d5, .gu = 0x038b, .bu = 0x0100, .au = 0x0f00,
+       .rv = 0x0100, .gv = 0x03d1, .bv = 0x06bc, .av = 0x0f00,
+};
+
+static const struct color_conversion hdtv_csc_rgb = {
+       .ry = 0x0000, .gy = 0x0f00, .by = 0x0000, .ay = 0x0166,
+       .ru = 0x0000, .gu = 0x0000, .bu = 0x0f00, .au = 0x0166,
+       .rv = 0x0f00, .gv = 0x0000, .bv = 0x0000, .av = 0x0166,
+};
+
+static const struct video_levels component_levels = {
+       .blank = 279, .black = 279, .burst = 0,
+};
+
+
+struct tv_mode {
+       char *name;
+       int clock;
+       int refresh; /* in millihertz (for precision) */
+       u32 oversample;
+       int hsync_end, hblank_start, hblank_end, htotal;
+       bool progressive, trilevel_sync, component_only;
+       int vsync_start_f1, vsync_start_f2, vsync_len;
+       bool veq_ena;
+       int veq_start_f1, veq_start_f2, veq_len;
+       int vi_end_f1, vi_end_f2, nbr_end;
+       bool burst_ena;
+       int hburst_start, hburst_len;
+       int vburst_start_f1, vburst_end_f1;
+       int vburst_start_f2, vburst_end_f2;
+       int vburst_start_f3, vburst_end_f3;
+       int vburst_start_f4, vburst_end_f4;
+       /*
+        * subcarrier programming
+        */
+       int dda2_size, dda3_size, dda1_inc, dda2_inc, dda3_inc;
+       u32 sc_reset;
+       bool pal_burst;
+       /*
+        * blank/black levels
+        */
+       const struct video_levels *composite_levels, *svideo_levels;
+       const struct color_conversion *composite_color, *svideo_color;
+       const u32 *filter_table;
+       int max_srcw;
+};
+
+
+/*
+ * Sub carrier DDA
+ *
+ *  I think this works as follows:
+ *
+ *  subcarrier freq = pixel_clock * (dda1_inc + dda2_inc / dda2_size) / 4096
+ *
+ * Presumably, when dda3 is added in, it gets to adjust the dda2_inc value
+ *
+ * So,
+ *  dda1_ideal = subcarrier/pixel * 4096
+ *  dda1_inc = floor (dda1_ideal)
+ *  dda2 = dda1_ideal - dda1_inc
+ *
+ *  then pick a ratio for dda2 that gives the closest approximation. If
+ *  you can't get close enough, you can play with dda3 as well. This
+ *  seems likely to happen when dda2 is small as the jumps would be larger
+ *
+ * To invert this,
+ *
+ *  pixel_clock = subcarrier * 4096 / (dda1_inc + dda2_inc / dda2_size)
+ *
+ * The constants below were all computed using a 107.520MHz clock
+ */
+/**
+ * Register programming values for TV modes.
+ *
+ * These values account for -1s required.
+ */
+
+const static struct tv_mode tv_modes[] = {
+       {
+               .name           = "NTSC-M",
+               .clock          = 107520,       
+               .refresh        = 29970,
+               .oversample     = TV_OVERSAMPLE_8X,
+               .component_only = 0,
+               /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
+
+               .hsync_end      = 64,               .hblank_end         = 124,
+               .hblank_start   = 836,              .htotal             = 857,
+
+               .progressive    = FALSE,            .trilevel_sync = FALSE,
+
+               .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
+               .vsync_len      = 6,
+
+               .veq_ena        = TRUE,             .veq_start_f1       = 0,
+               .veq_start_f2   = 1,                .veq_len            = 18,
+
+               .vi_end_f1      = 20,               .vi_end_f2          = 21,
+               .nbr_end        = 240,
+
+               .burst_ena      = TRUE,
+               .hburst_start   = 72,               .hburst_len         = 34,
+               .vburst_start_f1 = 9,               .vburst_end_f1      = 240,
+               .vburst_start_f2 = 10,              .vburst_end_f2      = 240,
+               .vburst_start_f3 = 9,               .vburst_end_f3      = 240, 
+               .vburst_start_f4 = 10,              .vburst_end_f4      = 240,
+
+               /* desired 3.5800000 actual 3.5800000 clock 107.52 */
+               .dda1_inc       =    136,
+               .dda2_inc       =   7624,           .dda2_size          =  20013,
+               .dda3_inc       =      0,           .dda3_size          =      0,
+               .sc_reset       = TV_SC_RESET_EVERY_4,
+               .pal_burst      = FALSE,
+
+               .composite_levels = &ntsc_m_levels_composite,
+               .composite_color = &ntsc_m_csc_composite,
+               .svideo_levels  = &ntsc_m_levels_svideo,
+               .svideo_color = &ntsc_m_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name           = "NTSC-443",
+               .clock          = 107520,       
+               .refresh        = 29970,
+               .oversample     = TV_OVERSAMPLE_8X,
+               .component_only = 0,
+               /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */
+               .hsync_end      = 64,               .hblank_end         = 124,
+               .hblank_start   = 836,              .htotal             = 857,
+
+               .progressive    = FALSE,            .trilevel_sync = FALSE,
+
+               .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
+               .vsync_len      = 6,
+
+               .veq_ena        = TRUE,             .veq_start_f1       = 0,
+               .veq_start_f2   = 1,                .veq_len            = 18,
+
+               .vi_end_f1      = 20,               .vi_end_f2          = 21,
+               .nbr_end        = 240,
+
+               .burst_ena      = 8,
+               .hburst_start   = 72,               .hburst_len         = 34,
+               .vburst_start_f1 = 9,               .vburst_end_f1      = 240,
+               .vburst_start_f2 = 10,              .vburst_end_f2      = 240,
+               .vburst_start_f3 = 9,               .vburst_end_f3      = 240, 
+               .vburst_start_f4 = 10,              .vburst_end_f4      = 240,
+
+               /* desired 4.4336180 actual 4.4336180 clock 107.52 */
+               .dda1_inc       =    168,
+               .dda2_inc       =  18557,       .dda2_size      =  20625,
+               .dda3_inc       =      0,       .dda3_size      =      0,
+               .sc_reset   = TV_SC_RESET_EVERY_8,
+               .pal_burst  = TRUE,
+
+               .composite_levels = &ntsc_m_levels_composite,
+               .composite_color = &ntsc_m_csc_composite,
+               .svideo_levels  = &ntsc_m_levels_svideo,
+               .svideo_color = &ntsc_m_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name           = "NTSC-J",
+               .clock          = 107520,       
+               .refresh        = 29970,
+               .oversample     = TV_OVERSAMPLE_8X,
+               .component_only = 0,
+
+               /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
+               .hsync_end      = 64,               .hblank_end         = 124,
+               .hblank_start = 836,        .htotal             = 857,
+
+               .progressive    = FALSE,    .trilevel_sync = FALSE,
+
+               .vsync_start_f1 = 6,        .vsync_start_f2     = 7,
+               .vsync_len      = 6,
+
+               .veq_ena        = TRUE,             .veq_start_f1       = 0,
+               .veq_start_f2 = 1,          .veq_len            = 18,
+
+               .vi_end_f1      = 20,               .vi_end_f2          = 21,
+               .nbr_end        = 240,
+
+               .burst_ena      = TRUE,
+               .hburst_start   = 72,               .hburst_len         = 34,
+               .vburst_start_f1 = 9,               .vburst_end_f1      = 240,
+               .vburst_start_f2 = 10,              .vburst_end_f2      = 240,
+               .vburst_start_f3 = 9,               .vburst_end_f3      = 240, 
+               .vburst_start_f4 = 10,              .vburst_end_f4      = 240,
+
+               /* desired 3.5800000 actual 3.5800000 clock 107.52 */
+               .dda1_inc       =    136,
+               .dda2_inc       =   7624,           .dda2_size          =  20013,
+               .dda3_inc       =      0,           .dda3_size          =      0,
+               .sc_reset       = TV_SC_RESET_EVERY_4,
+               .pal_burst      = FALSE,
+
+               .composite_levels = &ntsc_j_levels_composite,
+               .composite_color = &ntsc_j_csc_composite,
+               .svideo_levels  = &ntsc_j_levels_svideo,
+               .svideo_color = &ntsc_j_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name           = "PAL-M",
+               .clock          = 107520,       
+               .refresh        = 29970,
+               .oversample     = TV_OVERSAMPLE_8X,
+               .component_only = 0,
+
+               /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */
+               .hsync_end      = 64,             .hblank_end           = 124,
+               .hblank_start = 836,      .htotal               = 857,
+
+               .progressive    = FALSE,            .trilevel_sync = FALSE,
+
+               .vsync_start_f1 = 6,                .vsync_start_f2     = 7,
+               .vsync_len      = 6,
+
+               .veq_ena        = TRUE,             .veq_start_f1       = 0,
+               .veq_start_f2   = 1,                .veq_len            = 18,
+
+               .vi_end_f1      = 20,               .vi_end_f2          = 21,
+               .nbr_end        = 240,
+
+               .burst_ena      = TRUE,
+               .hburst_start   = 72,               .hburst_len         = 34,
+               .vburst_start_f1 = 9,               .vburst_end_f1      = 240,
+               .vburst_start_f2 = 10,              .vburst_end_f2      = 240,
+               .vburst_start_f3 = 9,               .vburst_end_f3      = 240, 
+               .vburst_start_f4 = 10,              .vburst_end_f4      = 240,
+
+               /* desired 3.5800000 actual 3.5800000 clock 107.52 */
+               .dda1_inc       =    136,
+               .dda2_inc       =    7624,          .dda2_size          =  20013,
+               .dda3_inc       =      0,           .dda3_size          =      0,
+               .sc_reset       = TV_SC_RESET_EVERY_4,
+               .pal_burst  = FALSE,
+
+               .composite_levels = &pal_m_levels_composite,
+               .composite_color = &pal_m_csc_composite,
+               .svideo_levels  = &pal_m_levels_svideo,
+               .svideo_color = &pal_m_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
+               .name       = "PAL-N",
+               .clock          = 107520,       
+               .refresh        = 25000,
+               .oversample     = TV_OVERSAMPLE_8X,
+               .component_only = 0,
+
+               .hsync_end      = 64,               .hblank_end         = 128,
+               .hblank_start = 844,        .htotal             = 863,
+
+               .progressive  = FALSE,    .trilevel_sync = FALSE,
+
+
+               .vsync_start_f1 = 6,       .vsync_start_f2      = 7,
+               .vsync_len      = 6,
+
+               .veq_ena        = TRUE,             .veq_start_f1       = 0,
+               .veq_start_f2   = 1,                .veq_len            = 18,
+
+               .vi_end_f1      = 24,               .vi_end_f2          = 25,
+               .nbr_end        = 286,
+
+               .burst_ena      = TRUE,
+               .hburst_start = 73,                 .hburst_len         = 34,
+               .vburst_start_f1 = 8,       .vburst_end_f1      = 285,
+               .vburst_start_f2 = 8,       .vburst_end_f2      = 286,
+               .vburst_start_f3 = 9,       .vburst_end_f3      = 286, 
+               .vburst_start_f4 = 9,       .vburst_end_f4      = 285,
+
+
+               /* desired 4.4336180 actual 4.4336180 clock 107.52 */
+               .dda1_inc       =    168,
+               .dda2_inc       =  18557,       .dda2_size      =  20625,
+               .dda3_inc       =      0,       .dda3_size      =      0,
+               .sc_reset   = TV_SC_RESET_EVERY_8,
+               .pal_burst  = TRUE,
+
+               .composite_levels = &pal_n_levels_composite,
+               .composite_color = &pal_n_csc_composite,
+               .svideo_levels  = &pal_n_levels_svideo,
+               .svideo_color = &pal_n_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */
+               .name       = "PAL",
+               .clock          = 107520,       
+               .refresh        = 25000,
+               .oversample     = TV_OVERSAMPLE_8X,
+               .component_only = 0,
+
+               .hsync_end      = 64,               .hblank_end         = 128,
+               .hblank_start   = 844,      .htotal             = 863,
+
+               .progressive    = FALSE,    .trilevel_sync = FALSE,
+
+               .vsync_start_f1 = 5,        .vsync_start_f2     = 6,
+               .vsync_len      = 5,
+
+               .veq_ena        = TRUE,             .veq_start_f1       = 0,
+               .veq_start_f2   = 1,        .veq_len            = 15,
+
+               .vi_end_f1      = 24,               .vi_end_f2          = 25,
+               .nbr_end        = 286,
+
+               .burst_ena      = TRUE,
+               .hburst_start   = 73,               .hburst_len         = 32,
+               .vburst_start_f1 = 8,               .vburst_end_f1      = 285,
+               .vburst_start_f2 = 8,               .vburst_end_f2      = 286,
+               .vburst_start_f3 = 9,               .vburst_end_f3      = 286, 
+               .vburst_start_f4 = 9,               .vburst_end_f4      = 285,
+
+               /* desired 4.4336180 actual 4.4336180 clock 107.52 */
+               .dda1_inc       =    168,
+               .dda2_inc       =  18557,       .dda2_size      =  20625,
+               .dda3_inc       =      0,       .dda3_size      =      0,
+               .sc_reset   = TV_SC_RESET_EVERY_8,
+               .pal_burst  = TRUE,
+
+               .composite_levels = &pal_levels_composite,
+               .composite_color = &pal_csc_composite,
+               .svideo_levels  = &pal_levels_svideo,
+               .svideo_color = &pal_csc_svideo,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "480p@59.94Hz",
+               .clock  = 107520,       
+               .refresh        = 59940,
+               .oversample     = TV_OVERSAMPLE_4X,
+               .component_only = 1,
+
+               .hsync_end      = 64,               .hblank_end         = 122,
+               .hblank_start   = 842,              .htotal             = 857,
+
+               .progressive    = TRUE,.trilevel_sync = FALSE,
+
+               .vsync_start_f1 = 12,               .vsync_start_f2     = 12,
+               .vsync_len      = 12,
+
+               .veq_ena        = FALSE,
+
+               .vi_end_f1      = 44,               .vi_end_f2          = 44,
+               .nbr_end        = 496,
+
+               .burst_ena      = FALSE,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "480p@60Hz",
+               .clock  = 107520,       
+               .refresh        = 60000,
+               .oversample     = TV_OVERSAMPLE_4X,
+               .component_only = 1,
+
+               .hsync_end      = 64,               .hblank_end         = 122,
+               .hblank_start   = 842,              .htotal             = 856,
+
+               .progressive    = TRUE,.trilevel_sync = FALSE,
+
+               .vsync_start_f1 = 12,               .vsync_start_f2     = 12,
+               .vsync_len      = 12,
+
+               .veq_ena        = FALSE,
+
+               .vi_end_f1      = 44,               .vi_end_f2          = 44,
+               .nbr_end        = 496,
+
+               .burst_ena      = FALSE,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "576p",
+               .clock  = 107520,       
+               .refresh        = 50000,
+               .oversample     = TV_OVERSAMPLE_4X,
+               .component_only = 1,
+
+               .hsync_end      = 64,               .hblank_end         = 139,
+               .hblank_start   = 859,              .htotal             = 863,
+
+               .progressive    = TRUE,         .trilevel_sync = FALSE,
+
+               .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
+               .vsync_len      = 10,
+
+               .veq_ena        = FALSE,
+
+               .vi_end_f1      = 48,               .vi_end_f2          = 48,
+               .nbr_end        = 575,
+
+               .burst_ena      = FALSE,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "720p@60Hz",
+               .clock          = 148800,       
+               .refresh        = 60000,
+               .oversample     = TV_OVERSAMPLE_2X,
+               .component_only = 1,
+
+               .hsync_end      = 80,               .hblank_end         = 300,
+               .hblank_start   = 1580,             .htotal             = 1649,
+
+               .progressive    = TRUE,             .trilevel_sync = TRUE,
+
+               .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
+               .vsync_len      = 10,
+
+               .veq_ena        = FALSE,
+
+               .vi_end_f1      = 29,               .vi_end_f2          = 29,
+               .nbr_end        = 719,
+
+               .burst_ena      = FALSE,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "720p@59.94Hz",
+               .clock          = 148800,       
+               .refresh        = 59940,
+               .oversample     = TV_OVERSAMPLE_2X,
+               .component_only = 1,
+
+               .hsync_end      = 80,               .hblank_end         = 300,
+               .hblank_start   = 1580,             .htotal             = 1651,
+
+               .progressive    = TRUE,             .trilevel_sync = TRUE,
+
+               .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
+               .vsync_len      = 10,
+
+               .veq_ena        = FALSE,
+
+               .vi_end_f1      = 29,               .vi_end_f2          = 29,
+               .nbr_end        = 719,
+
+               .burst_ena      = FALSE,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "720p@50Hz",
+               .clock          = 148800,       
+               .refresh        = 50000,
+               .oversample     = TV_OVERSAMPLE_2X,
+               .component_only = 1,
+
+               .hsync_end      = 80,               .hblank_end         = 300,
+               .hblank_start   = 1580,             .htotal             = 1979,
+
+               .progressive    = TRUE,                 .trilevel_sync = TRUE,
+
+               .vsync_start_f1 = 10,               .vsync_start_f2     = 10,
+               .vsync_len      = 10,
+
+               .veq_ena        = FALSE,
+
+               .vi_end_f1      = 29,               .vi_end_f2          = 29,
+               .nbr_end        = 719,
+
+               .burst_ena      = FALSE,
+
+               .filter_table = filter_table,
+               .max_srcw = 800
+       },
+       {
+               .name       = "1080i@50Hz",
+               .clock          = 148800,       
+               .refresh        = 25000,
+               .oversample     = TV_OVERSAMPLE_2X,
+               .component_only = 1,
+
+               .hsync_end      = 88,               .hblank_end         = 235,
+               .hblank_start   = 2155,             .htotal             = 2639,
+
+               .progressive    = FALSE,            .trilevel_sync = TRUE,
+
+               .vsync_start_f1 = 4,              .vsync_start_f2     = 5,
+               .vsync_len      = 10,
+
+               .veq_ena        = TRUE,             .veq_start_f1       = 4,
+               .veq_start_f2   = 4,        .veq_len            = 10,
+
+
+               .vi_end_f1      = 21,           .vi_end_f2          = 22,
+               .nbr_end        = 539,
+
+               .burst_ena      = FALSE,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "1080i@60Hz",
+               .clock          = 148800,       
+               .refresh        = 30000,
+               .oversample     = TV_OVERSAMPLE_2X,
+               .component_only = 1,
+
+               .hsync_end      = 88,               .hblank_end         = 235,
+               .hblank_start   = 2155,             .htotal             = 2199,
+
+               .progressive    = FALSE,            .trilevel_sync = TRUE,
+
+               .vsync_start_f1 = 4,               .vsync_start_f2     = 5,
+               .vsync_len      = 10,
+
+               .veq_ena        = TRUE,             .veq_start_f1       = 4,
+               .veq_start_f2   = 4,                .veq_len            = 10,
+
+
+               .vi_end_f1      = 21,               .vi_end_f2          = 22,
+               .nbr_end        = 539,
+
+               .burst_ena      = FALSE,
+
+               .filter_table = filter_table,
+       },
+       {
+               .name       = "1080i@59.94Hz",
+               .clock          = 148800,       
+               .refresh        = 29970,
+               .oversample     = TV_OVERSAMPLE_2X,
+               .component_only = 1,
+
+               .hsync_end      = 88,               .hblank_end         = 235,
+               .hblank_start   = 2155,             .htotal             = 2200,
+
+               .progressive    = FALSE,            .trilevel_sync = TRUE,
+
+               .vsync_start_f1 = 4,            .vsync_start_f2    = 5,
+               .vsync_len      = 10,
+
+               .veq_ena        = TRUE,             .veq_start_f1       = 4,
+               .veq_start_f2 = 4,                  .veq_len = 10,
+
+
+               .vi_end_f1      = 21,           .vi_end_f2              = 22,
+               .nbr_end        = 539,
+
+               .burst_ena      = FALSE,
+
+               .filter_table = filter_table,
+       },
+};
+
+#define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0])
+
+static void
+intel_tv_dpms(struct drm_output *output, int mode)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       switch(mode) {
+       case DPMSModeOn:
+               I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE);
+               break;
+       case DPMSModeStandby:
+       case DPMSModeSuspend:
+       case DPMSModeOff:
+               I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE);
+               break;
+       }
+}
+
+static void
+intel_tv_save(struct drm_output *output)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+       int i;
+
+       tv_priv->save_TV_H_CTL_1 = I915_READ(TV_H_CTL_1);
+       tv_priv->save_TV_H_CTL_2 = I915_READ(TV_H_CTL_2);
+       tv_priv->save_TV_H_CTL_3 = I915_READ(TV_H_CTL_3);
+       tv_priv->save_TV_V_CTL_1 = I915_READ(TV_V_CTL_1);
+       tv_priv->save_TV_V_CTL_2 = I915_READ(TV_V_CTL_2);
+       tv_priv->save_TV_V_CTL_3 = I915_READ(TV_V_CTL_3);
+       tv_priv->save_TV_V_CTL_4 = I915_READ(TV_V_CTL_4);
+       tv_priv->save_TV_V_CTL_5 = I915_READ(TV_V_CTL_5);
+       tv_priv->save_TV_V_CTL_6 = I915_READ(TV_V_CTL_6);
+       tv_priv->save_TV_V_CTL_7 = I915_READ(TV_V_CTL_7);
+       tv_priv->save_TV_SC_CTL_1 = I915_READ(TV_SC_CTL_1);
+       tv_priv->save_TV_SC_CTL_2 = I915_READ(TV_SC_CTL_2);
+       tv_priv->save_TV_SC_CTL_3 = I915_READ(TV_SC_CTL_3);
+
+       tv_priv->save_TV_CSC_Y = I915_READ(TV_CSC_Y);
+       tv_priv->save_TV_CSC_Y2 = I915_READ(TV_CSC_Y2);
+       tv_priv->save_TV_CSC_U = I915_READ(TV_CSC_U);
+       tv_priv->save_TV_CSC_U2 = I915_READ(TV_CSC_U2);
+       tv_priv->save_TV_CSC_V = I915_READ(TV_CSC_V);
+       tv_priv->save_TV_CSC_V2 = I915_READ(TV_CSC_V2);
+       tv_priv->save_TV_CLR_KNOBS = I915_READ(TV_CLR_KNOBS);
+       tv_priv->save_TV_CLR_LEVEL = I915_READ(TV_CLR_LEVEL);
+       tv_priv->save_TV_WIN_POS = I915_READ(TV_WIN_POS);
+       tv_priv->save_TV_WIN_SIZE = I915_READ(TV_WIN_SIZE);
+       tv_priv->save_TV_FILTER_CTL_1 = I915_READ(TV_FILTER_CTL_1);
+       tv_priv->save_TV_FILTER_CTL_2 = I915_READ(TV_FILTER_CTL_2);
+       tv_priv->save_TV_FILTER_CTL_3 = I915_READ(TV_FILTER_CTL_3);
+
+       for (i = 0; i < 60; i++)
+               tv_priv->save_TV_H_LUMA[i] = I915_READ(TV_H_LUMA_0 + (i <<2));
+       for (i = 0; i < 60; i++)
+               tv_priv->save_TV_H_CHROMA[i] = I915_READ(TV_H_CHROMA_0 + (i <<2));
+       for (i = 0; i < 43; i++)
+               tv_priv->save_TV_V_LUMA[i] = I915_READ(TV_V_LUMA_0 + (i <<2));
+       for (i = 0; i < 43; i++)
+               tv_priv->save_TV_V_CHROMA[i] = I915_READ(TV_V_CHROMA_0 + (i <<2));
+
+       tv_priv->save_TV_DAC = I915_READ(TV_DAC);
+       tv_priv->save_TV_CTL = I915_READ(TV_CTL);
+}
+
+static void
+intel_tv_restore(struct drm_output *output)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+       struct drm_crtc *crtc = output->crtc;
+       struct intel_crtc *intel_crtc;
+       int i;
+
+       /* FIXME: No CRTC? */
+       if (!crtc)
+               return;
+
+       intel_crtc = crtc->driver_private;
+       I915_WRITE(TV_H_CTL_1, tv_priv->save_TV_H_CTL_1);
+       I915_WRITE(TV_H_CTL_2, tv_priv->save_TV_H_CTL_2);
+       I915_WRITE(TV_H_CTL_3, tv_priv->save_TV_H_CTL_3);
+       I915_WRITE(TV_V_CTL_1, tv_priv->save_TV_V_CTL_1);
+       I915_WRITE(TV_V_CTL_2, tv_priv->save_TV_V_CTL_2);
+       I915_WRITE(TV_V_CTL_3, tv_priv->save_TV_V_CTL_3);
+       I915_WRITE(TV_V_CTL_4, tv_priv->save_TV_V_CTL_4);
+       I915_WRITE(TV_V_CTL_5, tv_priv->save_TV_V_CTL_5);
+       I915_WRITE(TV_V_CTL_6, tv_priv->save_TV_V_CTL_6);
+       I915_WRITE(TV_V_CTL_7, tv_priv->save_TV_V_CTL_7);
+       I915_WRITE(TV_SC_CTL_1, tv_priv->save_TV_SC_CTL_1);
+       I915_WRITE(TV_SC_CTL_2, tv_priv->save_TV_SC_CTL_2);
+       I915_WRITE(TV_SC_CTL_3, tv_priv->save_TV_SC_CTL_3);
+
+       I915_WRITE(TV_CSC_Y, tv_priv->save_TV_CSC_Y);
+       I915_WRITE(TV_CSC_Y2, tv_priv->save_TV_CSC_Y2);
+       I915_WRITE(TV_CSC_U, tv_priv->save_TV_CSC_U);
+       I915_WRITE(TV_CSC_U2, tv_priv->save_TV_CSC_U2);
+       I915_WRITE(TV_CSC_V, tv_priv->save_TV_CSC_V);
+       I915_WRITE(TV_CSC_V2, tv_priv->save_TV_CSC_V2);
+       I915_WRITE(TV_CLR_KNOBS, tv_priv->save_TV_CLR_KNOBS);
+       I915_WRITE(TV_CLR_LEVEL, tv_priv->save_TV_CLR_LEVEL);
+
+       {
+               int pipeconf_reg = (intel_crtc->pipe == 0) ?
+                       PIPEACONF : PIPEBCONF;
+               int dspcntr_reg = (intel_crtc->plane == 0) ?
+                       DSPACNTR : DSPBCNTR;
+               int pipeconf = I915_READ(pipeconf_reg);
+               int dspcntr = I915_READ(dspcntr_reg);
+               int dspbase_reg = (intel_crtc->plane == 0) ?
+                       DSPABASE : DSPBBASE;
+               /* Pipe must be off here */
+               I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE);
+               /* Flush the plane changes */
+               I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
+
+               if (!IS_I9XX(dev)) {
+                       /* Wait for vblank for the disable to take effect */
+                       intel_wait_for_vblank(dev);
+               }
+
+               I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
+               /* Wait for vblank for the disable to take effect. */
+               intel_wait_for_vblank(dev);
+
+               /* Filter ctl must be set before TV_WIN_SIZE */
+               I915_WRITE(TV_FILTER_CTL_1, tv_priv->save_TV_FILTER_CTL_1);
+               I915_WRITE(TV_FILTER_CTL_2, tv_priv->save_TV_FILTER_CTL_2);
+               I915_WRITE(TV_FILTER_CTL_3, tv_priv->save_TV_FILTER_CTL_3);
+               I915_WRITE(TV_WIN_POS, tv_priv->save_TV_WIN_POS);
+               I915_WRITE(TV_WIN_SIZE, tv_priv->save_TV_WIN_SIZE);
+               I915_WRITE(pipeconf_reg, pipeconf);
+               I915_WRITE(dspcntr_reg, dspcntr);
+               /* Flush the plane changes */
+               I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
+       }
+
+       for (i = 0; i < 60; i++)
+               I915_WRITE(TV_H_LUMA_0 + (i <<2), tv_priv->save_TV_H_LUMA[i]);
+       for (i = 0; i < 60; i++)
+               I915_WRITE(TV_H_CHROMA_0 + (i <<2), tv_priv->save_TV_H_CHROMA[i]);
+       for (i = 0; i < 43; i++)
+               I915_WRITE(TV_V_LUMA_0 + (i <<2), tv_priv->save_TV_V_LUMA[i]);
+       for (i = 0; i < 43; i++)
+               I915_WRITE(TV_V_CHROMA_0 + (i <<2), tv_priv->save_TV_V_CHROMA[i]);
+
+       I915_WRITE(TV_DAC, tv_priv->save_TV_DAC);
+       I915_WRITE(TV_CTL, tv_priv->save_TV_CTL);
+}
+
+static const struct tv_mode *
+intel_tv_mode_lookup (char *tv_format)
+{
+       int i;
+    
+       for (i = 0; i < sizeof(tv_modes) / sizeof (tv_modes[0]); i++) {
+               const struct tv_mode *tv_mode = &tv_modes[i];
+
+               if (!strcmp(tv_format, tv_mode->name))
+                       return tv_mode;
+       }
+       return NULL;
+}
+
+static const struct tv_mode *
+intel_tv_mode_find (struct drm_output *output)
+{
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+
+       return intel_tv_mode_lookup(tv_priv->tv_format);
+}
+
+static enum drm_mode_status
+intel_tv_mode_valid(struct drm_output *output, struct drm_display_mode *mode)
+{
+       const struct tv_mode *tv_mode = intel_tv_mode_find(output);
+
+       /* Ensure TV refresh is close to desired refresh */
+       if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 1)
+               return MODE_OK;
+       return MODE_CLOCK_RANGE;
+}
+
+
+static bool
+intel_tv_mode_fixup(struct drm_output *output, struct drm_display_mode *mode,
+                   struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_mode_config *drm_config = &dev->mode_config;
+       const struct tv_mode *tv_mode = intel_tv_mode_find (output);
+       struct drm_output *other_output;
+
+       if (!tv_mode)
+               return FALSE;
+    
+       /* FIXME: lock output list */
+       list_for_each_entry(other_output, &drm_config->output_list, head) {
+               if (other_output != output &&
+                   other_output->crtc == output->crtc)
+                       return FALSE;
+       }
+
+       adjusted_mode->clock = tv_mode->clock;
+       return TRUE;
+}
+
+static void
+intel_tv_mode_set(struct drm_output *output, struct drm_display_mode *mode,
+                 struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = output->crtc;
+       struct intel_crtc *intel_crtc = crtc->driver_private;
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+       const struct tv_mode *tv_mode = intel_tv_mode_find(output);
+       u32 tv_ctl;
+       u32 hctl1, hctl2, hctl3;
+       u32 vctl1, vctl2, vctl3, vctl4, vctl5, vctl6, vctl7;
+       u32 scctl1, scctl2, scctl3;
+       int i, j;
+       const struct video_levels *video_levels;
+       const struct color_conversion *color_conversion;
+       bool burst_ena;
+    
+       if (!tv_mode)
+               return; /* can't happen (mode_prepare prevents this) */
+    
+       tv_ctl = 0;
+
+       switch (tv_priv->type) {
+       default:
+       case TV_TYPE_UNKNOWN:
+       case TV_TYPE_COMPOSITE:
+               tv_ctl |= TV_ENC_OUTPUT_COMPOSITE;
+               video_levels = tv_mode->composite_levels;
+               color_conversion = tv_mode->composite_color;
+               burst_ena = tv_mode->burst_ena;
+               break;
+       case TV_TYPE_COMPONENT:
+               tv_ctl |= TV_ENC_OUTPUT_COMPONENT;
+               video_levels = &component_levels;
+               if (tv_mode->burst_ena)
+                       color_conversion = &sdtv_csc_yprpb;
+               else
+                       color_conversion = &hdtv_csc_yprpb;
+               burst_ena = FALSE;
+               break;
+       case TV_TYPE_SVIDEO:
+               tv_ctl |= TV_ENC_OUTPUT_SVIDEO;
+               video_levels = tv_mode->svideo_levels;
+               color_conversion = tv_mode->svideo_color;
+               burst_ena = tv_mode->burst_ena;
+               break;
+       }
+       hctl1 = (tv_mode->hsync_end << TV_HSYNC_END_SHIFT) |
+               (tv_mode->htotal << TV_HTOTAL_SHIFT);
+
+       hctl2 = (tv_mode->hburst_start << 16) |
+               (tv_mode->hburst_len << TV_HBURST_LEN_SHIFT);
+
+       if (burst_ena)
+               hctl2 |= TV_BURST_ENA;
+
+       hctl3 = (tv_mode->hblank_start << TV_HBLANK_START_SHIFT) |
+               (tv_mode->hblank_end << TV_HBLANK_END_SHIFT);
+
+       vctl1 = (tv_mode->nbr_end << TV_NBR_END_SHIFT) |
+               (tv_mode->vi_end_f1 << TV_VI_END_F1_SHIFT) |
+               (tv_mode->vi_end_f2 << TV_VI_END_F2_SHIFT);
+
+       vctl2 = (tv_mode->vsync_len << TV_VSYNC_LEN_SHIFT) |
+               (tv_mode->vsync_start_f1 << TV_VSYNC_START_F1_SHIFT) |
+               (tv_mode->vsync_start_f2 << TV_VSYNC_START_F2_SHIFT);
+
+       vctl3 = (tv_mode->veq_len << TV_VEQ_LEN_SHIFT) |
+               (tv_mode->veq_start_f1 << TV_VEQ_START_F1_SHIFT) |
+               (tv_mode->veq_start_f2 << TV_VEQ_START_F2_SHIFT);
+
+       if (tv_mode->veq_ena)
+               vctl3 |= TV_EQUAL_ENA;
+
+       vctl4 = (tv_mode->vburst_start_f1 << TV_VBURST_START_F1_SHIFT) |
+               (tv_mode->vburst_end_f1 << TV_VBURST_END_F1_SHIFT);
+
+       vctl5 = (tv_mode->vburst_start_f2 << TV_VBURST_START_F2_SHIFT) |
+               (tv_mode->vburst_end_f2 << TV_VBURST_END_F2_SHIFT);
+
+       vctl6 = (tv_mode->vburst_start_f3 << TV_VBURST_START_F3_SHIFT) |
+               (tv_mode->vburst_end_f3 << TV_VBURST_END_F3_SHIFT);
+
+       vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
+               (tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
+
+       if (intel_crtc->pipe == 1)
+               tv_ctl |= TV_ENC_PIPEB_SELECT;
+       tv_ctl |= tv_mode->oversample;
+
+       if (tv_mode->progressive)
+               tv_ctl |= TV_PROGRESSIVE;
+       if (tv_mode->trilevel_sync)
+               tv_ctl |= TV_TRILEVEL_SYNC;
+       if (tv_mode->pal_burst)
+               tv_ctl |= TV_PAL_BURST;
+       scctl1 = 0;
+       if (tv_mode->dda1_inc)
+               scctl1 |= TV_SC_DDA1_EN;
+
+       if (tv_mode->dda2_inc)
+               scctl1 |= TV_SC_DDA2_EN;
+
+       if (tv_mode->dda3_inc)
+               scctl1 |= TV_SC_DDA3_EN;
+
+       scctl1 |= tv_mode->sc_reset;
+       scctl1 |= video_levels->burst << TV_BURST_LEVEL_SHIFT;
+       scctl1 |= tv_mode->dda1_inc << TV_SCDDA1_INC_SHIFT;
+
+       scctl2 = tv_mode->dda2_size << TV_SCDDA2_SIZE_SHIFT |
+               tv_mode->dda2_inc << TV_SCDDA2_INC_SHIFT;
+
+       scctl3 = tv_mode->dda3_size << TV_SCDDA3_SIZE_SHIFT |
+               tv_mode->dda3_inc << TV_SCDDA3_INC_SHIFT;
+
+       /* Enable two fixes for the chips that need them. */
+       if (dev->pci_device < 0x2772)
+               tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
+
+       I915_WRITE(TV_H_CTL_1, hctl1);
+       I915_WRITE(TV_H_CTL_2, hctl2);
+       I915_WRITE(TV_H_CTL_3, hctl3);
+       I915_WRITE(TV_V_CTL_1, vctl1);
+       I915_WRITE(TV_V_CTL_2, vctl2);
+       I915_WRITE(TV_V_CTL_3, vctl3);
+       I915_WRITE(TV_V_CTL_4, vctl4);
+       I915_WRITE(TV_V_CTL_5, vctl5);
+       I915_WRITE(TV_V_CTL_6, vctl6);
+       I915_WRITE(TV_V_CTL_7, vctl7);
+       I915_WRITE(TV_SC_CTL_1, scctl1);
+       I915_WRITE(TV_SC_CTL_2, scctl2);
+       I915_WRITE(TV_SC_CTL_3, scctl3);
+
+       I915_WRITE(TV_CSC_Y, (color_conversion->ry << 16) |
+                  color_conversion->gy);
+       I915_WRITE(TV_CSC_Y2,(color_conversion->by << 16) |
+                  color_conversion->ay);
+       I915_WRITE(TV_CSC_U, (color_conversion->ru << 16) |
+                  color_conversion->gu);
+       I915_WRITE(TV_CSC_U2, (color_conversion->bu << 16) |
+                  color_conversion->au);
+       I915_WRITE(TV_CSC_V, (color_conversion->rv << 16) |
+                  color_conversion->gv);
+       I915_WRITE(TV_CSC_V2, (color_conversion->bv << 16) |
+                  color_conversion->av);
+
+       I915_WRITE(TV_CLR_KNOBS, 0x00606000);
+       I915_WRITE(TV_CLR_LEVEL, ((video_levels->black << TV_BLACK_LEVEL_SHIFT) |
+                             (video_levels->blank << TV_BLANK_LEVEL_SHIFT)));
+       {
+               int pipeconf_reg = (intel_crtc->pipe == 0) ?
+                       PIPEACONF : PIPEBCONF;
+               int dspcntr_reg = (intel_crtc->plane == 0) ?
+                       DSPACNTR : DSPBCNTR;
+               int pipeconf = I915_READ(pipeconf_reg);
+               int dspcntr = I915_READ(dspcntr_reg);
+               int dspbase_reg = (intel_crtc->plane == 0) ?
+                       DSPABASE : DSPBBASE;
+               int xpos = 0x0, ypos = 0x0;
+               unsigned int xsize, ysize;
+               /* Pipe must be off here */
+               I915_WRITE(dspcntr_reg, dspcntr & ~DISPLAY_PLANE_ENABLE);
+               /* Flush the plane changes */
+               I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
+
+               /* Wait for vblank for the disable to take effect */
+               if (!IS_I9XX(dev))
+                       intel_wait_for_vblank(dev);
+
+               I915_WRITE(pipeconf_reg, pipeconf & ~PIPEACONF_ENABLE);
+               /* Wait for vblank for the disable to take effect. */
+               intel_wait_for_vblank(dev);
+
+               /* Filter ctl must be set before TV_WIN_SIZE */
+               I915_WRITE(TV_FILTER_CTL_1, TV_AUTO_SCALE); 
+               xsize = tv_mode->hblank_start - tv_mode->hblank_end;
+               if (tv_mode->progressive)
+                       ysize = tv_mode->nbr_end + 1;
+               else
+                       ysize = 2*tv_mode->nbr_end + 1;
+
+               xpos += tv_priv->margin[TV_MARGIN_LEFT];
+               ypos += tv_priv->margin[TV_MARGIN_TOP];
+               xsize -= (tv_priv->margin[TV_MARGIN_LEFT] + 
+                         tv_priv->margin[TV_MARGIN_RIGHT]);
+               ysize -= (tv_priv->margin[TV_MARGIN_TOP] + 
+                         tv_priv->margin[TV_MARGIN_BOTTOM]);
+               I915_WRITE(TV_WIN_POS, (xpos<<16)|ypos);
+               I915_WRITE(TV_WIN_SIZE, (xsize<<16)|ysize);
+
+               I915_WRITE(pipeconf_reg, pipeconf);
+               I915_WRITE(dspcntr_reg, dspcntr);
+               /* Flush the plane changes */
+               I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
+       }       
+
+       j = 0;
+       for (i = 0; i < 60; i++)
+               I915_WRITE(TV_H_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
+       for (i = 0; i < 60; i++)
+               I915_WRITE(TV_H_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
+       for (i = 0; i < 43; i++)
+               I915_WRITE(TV_V_LUMA_0 + (i<<2), tv_mode->filter_table[j++]);
+       for (i = 0; i < 43; i++)
+               I915_WRITE(TV_V_CHROMA_0 + (i<<2), tv_mode->filter_table[j++]);
+       I915_WRITE(TV_DAC, 0);
+       I915_WRITE(TV_CTL, tv_ctl);
+}
+
+static const struct drm_display_mode reported_modes[] = {
+       {
+               .name = "NTSC 480i",
+               .clock = 107520,
+               .hdisplay = 1280,
+               .hsync_start = 1368,
+               .hsync_end = 1496,
+               .htotal = 1712,
+
+               .vdisplay = 1024,
+               .vsync_start = 1027,
+               .vsync_end = 1034,
+               .vtotal = 1104,
+               .type = DRM_MODE_TYPE_DRIVER,
+       },
+};
+
+/**
+ * Detects TV presence by checking for load.
+ *
+ * Requires that the current pipe's DPLL is active.
+
+ * \return TRUE if TV is connected.
+ * \return FALSE if TV is disconnected.
+ */
+static int
+intel_tv_detect_type (struct drm_crtc *crtc, struct drm_output *output)
+{
+       struct drm_device *dev = output->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_output *intel_output = output->driver_private;
+       u32 tv_ctl, save_tv_ctl;
+       u32 tv_dac, save_tv_dac;
+       int type = TV_TYPE_UNKNOWN;
+
+       tv_dac = I915_READ(TV_DAC);
+       /*
+        * Detect TV by polling)
+        */
+       if (intel_output->load_detect_temp) {
+               /* TV not currently running, prod it with destructive detect */
+               save_tv_dac = tv_dac;
+               tv_ctl = I915_READ(TV_CTL);
+               save_tv_ctl = tv_ctl;
+               tv_ctl &= ~TV_ENC_ENABLE;
+               tv_ctl &= ~TV_TEST_MODE_MASK;
+               tv_ctl |= TV_TEST_MODE_MONITOR_DETECT;
+               tv_dac &= ~TVDAC_SENSE_MASK;
+               tv_dac |= (TVDAC_STATE_CHG_EN |
+                          TVDAC_A_SENSE_CTL |
+                          TVDAC_B_SENSE_CTL |
+                          TVDAC_C_SENSE_CTL |
+                          DAC_CTL_OVERRIDE |
+                          DAC_A_0_7_V |
+                          DAC_B_0_7_V |
+                          DAC_C_0_7_V);
+               I915_WRITE(TV_CTL, tv_ctl);
+               I915_WRITE(TV_DAC, tv_dac);
+               intel_wait_for_vblank(dev);
+               tv_dac = I915_READ(TV_DAC);
+               I915_WRITE(TV_DAC, save_tv_dac);
+               I915_WRITE(TV_CTL, save_tv_ctl);
+       }
+       /*
+        *  A B C
+        *  0 1 1 Composite
+        *  1 0 X svideo
+        *  0 0 0 Component
+        */
+       if ((tv_dac & TVDAC_SENSE_MASK) == (TVDAC_B_SENSE | TVDAC_C_SENSE)) {
+               DRM_DEBUG("Detected Composite TV connection\n");
+               type = TV_TYPE_COMPOSITE;
+       } else if ((tv_dac & (TVDAC_A_SENSE|TVDAC_B_SENSE)) == TVDAC_A_SENSE) {
+               DRM_DEBUG("Detected S-Video TV connection\n");
+               type = TV_TYPE_SVIDEO;
+       } else if ((tv_dac & TVDAC_SENSE_MASK) == 0) {
+               DRM_DEBUG("Detected Component TV connection\n");
+               type = TV_TYPE_COMPONENT;
+       } else {
+               DRM_DEBUG("No TV connection detected\n");
+               type = TV_TYPE_NONE;
+       }
+
+       return type;
+}
+
+static int
+intel_tv_format_configure_property (struct drm_output *output);
+
+/**
+ * Detect the TV connection.
+ *
+ * Currently this always returns OUTPUT_STATUS_UNKNOWN, as we need to be sure
+ * we have a pipe programmed in order to probe the TV.
+ */
+static enum drm_output_status
+intel_tv_detect(struct drm_output *output)
+{
+       struct drm_crtc *crtc;
+       struct drm_display_mode mode;
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+       int dpms_mode;
+       int type = tv_priv->type;
+
+       mode = reported_modes[0];
+       drm_mode_set_crtcinfo(&mode, CRTC_INTERLACE_HALVE_V);
+#if 0
+       /* FIXME: pipe allocation for load detection */
+       crtc = i830GetLoadDetectPipe (output, &mode, &dpms_mode);
+       if (crtc) {
+               type = intel_tv_detect_type(crtc, output);
+               i830ReleaseLoadDetectPipe (output, dpms_mode);
+       }
+#endif
+       if (type != tv_priv->type) {
+               tv_priv->type = type;
+               intel_tv_format_configure_property (output);
+       }
+       
+       switch (type) {
+       case TV_TYPE_NONE:
+               return output_status_disconnected;
+       case TV_TYPE_UNKNOWN:
+               return output_status_unknown;
+       default:
+               return output_status_connected;
+       }
+}
+
+static struct input_res {
+       char *name;
+       int w, h;       
+} input_res_table[] = 
+{
+       {"640x480", 640, 480},
+       {"800x600", 800, 600},
+       {"1024x768", 1024, 768},
+       {"1280x1024", 1280, 1024},
+       {"848x480", 848, 480},
+       {"1280x720", 1280, 720},
+       {"1920x1080", 1920, 1080},
+};
+
+/**
+ * Stub get_modes function.
+ *
+ * This should probably return a set of fixed modes, unless we can figure out
+ * how to probe modes off of TV connections.
+ */
+
+static int
+intel_tv_get_modes(struct drm_output *output)
+{
+       struct drm_display_mode *mode_ptr;
+       const struct tv_mode *tv_mode = intel_tv_mode_find(output);
+       int j;
+
+       for (j = 0; j < sizeof(input_res_table) / sizeof(input_res_table[0]);
+            j++) {
+               struct input_res *input = &input_res_table[j];
+               unsigned int hactive_s = input->w;
+               unsigned int vactive_s = input->h;
+       
+               if (tv_mode->max_srcw && input->w > tv_mode->max_srcw)
+                       continue;
+
+               if (input->w > 1024 && (!tv_mode->progressive 
+                                       && !tv_mode->component_only))
+                       continue;
+
+               mode_ptr = drm_calloc(1, sizeof(struct drm_display_mode),
+                                     DRM_MEM_DRIVER);
+               strncpy(mode_ptr->name, input->name, DRM_DISPLAY_MODE_LEN);
+
+               mode_ptr->hdisplay = hactive_s;
+               mode_ptr->hsync_start = hactive_s + 1;
+               mode_ptr->hsync_end = hactive_s + 64;
+               if (mode_ptr->hsync_end <= mode_ptr->hsync_start)
+                       mode_ptr->hsync_end = mode_ptr->hsync_start + 1;
+               mode_ptr->htotal = hactive_s + 96;
+
+               mode_ptr->vdisplay = vactive_s;
+               mode_ptr->vsync_start = vactive_s + 1;
+               mode_ptr->vsync_end = vactive_s + 32;
+               if (mode_ptr->vsync_end <= mode_ptr->vsync_start)
+                       mode_ptr->vsync_end = mode_ptr->vsync_start  + 1;
+               mode_ptr->vtotal = vactive_s + 33;
+
+               mode_ptr->clock = (int) (tv_mode->refresh * 
+                                        mode_ptr->vtotal * 
+                                        mode_ptr->htotal / 1000) / 1000;
+       
+               mode_ptr->type = DRM_MODE_TYPE_DRIVER;
+               drm_mode_probed_add(output, mode_ptr);
+       } 
+
+       return 0;
+}
+
+static void
+intel_tv_destroy (struct drm_output *output)
+{
+       if (output->driver_private)
+               drm_free(output->driver_private, sizeof(struct intel_tv_priv),
+                        DRM_MEM_DRIVER);
+}
+
+static bool
+intel_tv_format_set_property(struct drm_output *output,
+                            struct drm_property *prop, uint64_t val)
+{
+#if 0
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+       const struct tv_mode *tv_mode =
+               intel_tv_mode_lookup(tv_priv->tv_format);
+       int                         err;
+
+       if (!tv_mode)
+               tv_mode = &tv_modes[0];
+       err = RRChangeOutputProperty (output->randr_output, tv_format_atom,
+                                     XA_ATOM, 32, PropModeReplace, 1,
+                                     &tv_format_name_atoms[tv_mode - tv_modes],
+                                     FALSE, TRUE);
+       return err == Success;
+#endif
+       return 0;
+}
+
+    
+/**
+ * Configure the TV_FORMAT property to list only supported formats
+ *
+ * Unless the connector is component, list only the formats supported by
+ * svideo and composite
+ */
+
+static int
+intel_tv_format_configure_property(struct drm_output *output)
+{
+#if 0
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+       Atom                current_atoms[NUM_TV_MODES];
+       int                         num_atoms = 0;
+       int                         i;
+    
+       if (!output->randr_output)
+               return Success;
+
+       for (i = 0; i < NUM_TV_MODES; i++)
+               if (!tv_modes[i].component_only ||
+                   tv_priv->type == TV_TYPE_COMPONENT)
+                       current_atoms[num_atoms++] = tv_format_name_atoms[i];
+    
+       return RRConfigureOutputProperty(output->randr_output, tv_format_atom,
+                                        TRUE, FALSE, FALSE, 
+                                        num_atoms, (INT32 *) current_atoms);
+#endif
+       return 0;
+}
+
+static void
+intel_tv_create_resources(struct drm_output *output)
+{
+       struct drm_device *dev = output->dev;
+       struct intel_output *intel_output = output->driver_private;
+       struct intel_tv_priv *tv_priv = intel_output->dev_priv;
+       int i, err;
+
+#if 0
+       /* Set up the tv_format property, which takes effect on mode set
+        * and accepts strings that match exactly
+        */
+       tv_format_atom = MakeAtom(TV_FORMAT_NAME, sizeof(TV_FORMAT_NAME) - 1,
+                                 TRUE);
+
+       for (i = 0; i < NUM_TV_MODES; i++)
+               tv_format_name_atoms[i] = MakeAtom (tv_modes[i].name,
+                                                   strlen (tv_modes[i].name),
+                                                   TRUE);
+
+       err = intel_tv_format_configure_property (output);
+
+       if (err != 0) {
+               xf86DrvMsg(dev->scrnIndex, X_ERROR,
+                          "RRConfigureOutputProperty error, %d\n", err);
+       }
+
+       /* Set the current value of the tv_format property */
+       if (!intel_tv_format_set_property (output))
+               xf86DrvMsg(dev->scrnIndex, X_ERROR,
+                          "RRChangeOutputProperty error, %d\n", err);
+
+       for (i = 0; i < 4; i++)
+       {
+               INT32   range[2];
+               margin_atoms[i] = MakeAtom(margin_names[i], strlen (margin_names[i]),
+                                          TRUE);
+
+               range[0] = 0;
+               range[1] = 100;
+               err = RRConfigureOutputProperty(output->randr_output, margin_atoms[i],
+                                               TRUE, TRUE, FALSE, 2, range);
+    
+               if (err != 0)
+                       xf86DrvMsg(dev->scrnIndex, X_ERROR,
+                                  "RRConfigureOutputProperty error, %d\n", err);
+
+               err = RRChangeOutputProperty(output->randr_output, margin_atoms[i],
+                                            XA_INTEGER, 32, PropModeReplace,
+                                            1, &tv_priv->margin[i],
+                                            FALSE, TRUE);
+               if (err != 0)
+                       xf86DrvMsg(dev->scrnIndex, X_ERROR,
+                                  "RRChangeOutputProperty error, %d\n", err);
+       }
+#endif
+}
+
+static bool
+intel_tv_set_property(struct drm_output *output, struct drm_property *property,
+                     uint64_t val)
+{
+       struct drm_device *dev = output->dev;
+       int ret = 0;
+    
+       if (property == dev->mode_config.tv_left_margin_property ||
+           property == dev->mode_config.tv_right_margin_property ||
+           property == dev->mode_config.tv_top_margin_property ||
+           property == dev->mode_config.tv_bottom_margin_property) {
+               ret = drm_output_property_set_value(output, property, val);
+       } else {
+               /* TV mode handling here */
+       }
+
+       return ret;
+}
+
+static const struct drm_output_funcs intel_tv_output_funcs = {
+       .dpms = intel_tv_dpms,
+       .save = intel_tv_save,
+       .restore = intel_tv_restore,
+       .mode_valid = intel_tv_mode_valid,
+       .mode_fixup = intel_tv_mode_fixup,
+       .prepare = intel_output_prepare,
+       .mode_set = intel_tv_mode_set,
+       .commit = intel_output_commit,
+       .detect = intel_tv_detect,
+       .get_modes = intel_tv_get_modes,
+       .cleanup = intel_tv_destroy,
+       .set_property = intel_tv_set_property,
+};
+
+void
+intel_tv_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_output *output;
+       struct intel_output *intel_output;
+       struct intel_tv_priv *tv_priv;
+       u32 tv_dac_on, tv_dac_off, save_tv_dac;
+
+       /* FIXME: better TV detection and/or quirks */
+#if 0
+       if (tv_priv->quirk_flag & QUIRK_IGNORE_TV)
+               return;
+#endif
+       if ((I915_READ(TV_CTL) & TV_FUSE_STATE_MASK) == TV_FUSE_STATE_DISABLED)
+               return;
+
+       /*
+        * Sanity check the TV output by checking to see if the
+        * DAC register holds a value
+        */
+       save_tv_dac = I915_READ(TV_DAC);
+
+       I915_WRITE(TV_DAC, save_tv_dac | TVDAC_STATE_CHG_EN);
+       tv_dac_on = I915_READ(TV_DAC);
+
+       I915_WRITE(TV_DAC, save_tv_dac & ~TVDAC_STATE_CHG_EN);
+       tv_dac_off = I915_READ(TV_DAC);
+
+       I915_WRITE(TV_DAC, save_tv_dac);
+
+       /*
+        * If the register does not hold the state change enable
+        * bit, (either as a 0 or a 1), assume it doesn't really
+        * exist
+        */
+       if ((tv_dac_on & TVDAC_STATE_CHG_EN) == 0 || 
+           (tv_dac_off & TVDAC_STATE_CHG_EN) != 0)
+               return;
+
+       output = drm_output_create(dev, &intel_tv_output_funcs,
+                                  DRM_MODE_OUTPUT_TVDAC);
+
+       if (!output)
+               return;
+
+       intel_output = drm_calloc(1, sizeof(struct intel_output) +
+                                 sizeof(struct intel_tv_priv), DRM_MEM_DRIVER);
+       if (!intel_output) {
+               drm_output_destroy(output);
+               return;
+       }
+
+       tv_priv = (struct intel_tv_priv *)(intel_output + 1);
+       intel_output->type = INTEL_OUTPUT_TVOUT;
+       output->possible_crtcs = ((1 << 0) | (1 << 1));
+       output->possible_clones = (1 << INTEL_OUTPUT_TVOUT);
+       intel_output->dev_priv = tv_priv;
+       tv_priv->type = TV_TYPE_UNKNOWN;
+
+       tv_priv->tv_format = NULL;
+    
+       /* BIOS margin values */
+       tv_priv->margin[TV_MARGIN_LEFT] = 54;
+       tv_priv->margin[TV_MARGIN_TOP] = 36;
+       tv_priv->margin[TV_MARGIN_RIGHT] = 46;
+       tv_priv->margin[TV_MARGIN_BOTTOM] = 37;
+    
+       if (!tv_priv->tv_format)
+               tv_priv->tv_format = kstrdup(tv_modes[0].name, GFP_KERNEL);
+    
+       output->driver_private = intel_output;
+       output->interlace_allowed = FALSE;
+       output->doublescan_allowed = FALSE;
+}
diff --git a/linux-core/radeon_ms.h b/linux-core/radeon_ms.h
new file mode 120000 (symlink)
index 0000000..da340c5
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms.h
\ No newline at end of file
diff --git a/linux-core/radeon_ms_bo.c b/linux-core/radeon_ms_bo.c
new file mode 120000 (symlink)
index 0000000..d05df59
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_bo.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_bus.c b/linux-core/radeon_ms_bus.c
new file mode 120000 (symlink)
index 0000000..50f649d
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_bus.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_combios.c b/linux-core/radeon_ms_combios.c
new file mode 120000 (symlink)
index 0000000..d7b9995
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_combios.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_combios.h b/linux-core/radeon_ms_combios.h
new file mode 120000 (symlink)
index 0000000..5b19c70
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_combios.h
\ No newline at end of file
diff --git a/linux-core/radeon_ms_compat.c b/linux-core/radeon_ms_compat.c
new file mode 100644 (file)
index 0000000..6efdc78
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2007 Dave Airlie
+ * Copyright 2007 Alex Deucher
+ * Copyright 2007 Michel Dänzer
+ * Copyright 2007 Roland Scheidegger
+ * Copyright 2007 Vladimir Dergachev
+ * Copyright 2007 Nicolai Haehnle
+ * Copyright 2007 Aapo Tahkola
+ * Copyright 2007 Ben Skeggs
+ * Copyright 2007 Jérôme Glisse
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ */
+/*
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_ms.h"
+
+/**
+ * Called whenever a 32-bit process running under a 64-bit kernel
+ * performs an ioctl on /dev/dri/card<n>.
+
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument.
+ * \return zero on success or negative number on failure.
+ */
+long radeon_ms_compat_ioctl(struct file *filp, unsigned int cmd,
+                           unsigned long arg)
+{
+       unsigned int nr = DRM_IOCTL_NR(cmd);
+       drm_ioctl_compat_t *fn = NULL;
+       int ret;
+
+       if (nr < DRM_COMMAND_BASE)
+               return drm_compat_ioctl(filp, cmd, arg);
+
+       lock_kernel();
+       if (fn != NULL)
+               ret = (*fn)(filp, cmd, arg);
+       else
+               ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+       unlock_kernel();
+
+       return ret;
+}
diff --git a/linux-core/radeon_ms_cp.c b/linux-core/radeon_ms_cp.c
new file mode 120000 (symlink)
index 0000000..6aee3e6
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_cp.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_cp_mc.c b/linux-core/radeon_ms_cp_mc.c
new file mode 120000 (symlink)
index 0000000..0ae1a64
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_cp_mc.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_crtc.c b/linux-core/radeon_ms_crtc.c
new file mode 120000 (symlink)
index 0000000..31f1144
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_crtc.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_dac.c b/linux-core/radeon_ms_dac.c
new file mode 120000 (symlink)
index 0000000..cb523cf
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_dac.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_drm.c b/linux-core/radeon_ms_drm.c
new file mode 120000 (symlink)
index 0000000..8bbf19a
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_drm.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_drm.h b/linux-core/radeon_ms_drm.h
new file mode 120000 (symlink)
index 0000000..5d9d731
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_drm.h
\ No newline at end of file
diff --git a/linux-core/radeon_ms_drv.c b/linux-core/radeon_ms_drv.c
new file mode 100644 (file)
index 0000000..d7b0eec
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2007 Jerome Glisse.
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ */
+/*
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#include "drm_pciids.h"
+#include "radeon_ms.h"
+
+extern struct drm_fence_driver radeon_ms_fence_driver;
+extern struct drm_bo_driver radeon_ms_bo_driver;
+extern struct drm_ioctl_desc radeon_ms_ioctls[];
+extern int radeon_ms_num_ioctls;
+
+static int radeon_ms_driver_dri_library_name(struct drm_device * dev,
+                                            char * buf);
+static int radeon_ms_driver_probe(struct pci_dev *pdev,
+                                 const struct pci_device_id *ent);
+
+static struct pci_device_id pciidlist[] = {
+       radeon_ms_PCI_IDS
+};
+
+static struct drm_driver driver = {
+       .load = radeon_ms_driver_load,
+       .firstopen = NULL,
+       .open = radeon_ms_driver_open,
+       .preclose = NULL,
+       .postclose = NULL,
+       .lastclose = radeon_ms_driver_lastclose,
+       .unload = radeon_ms_driver_unload,
+       .dma_ioctl = radeon_ms_driver_dma_ioctl,
+       .dma_ready = NULL,
+       .dma_quiescent = NULL,
+       .context_ctor = NULL,
+       .context_dtor = NULL,
+       .kernel_context_switch = NULL,
+       .kernel_context_switch_unlock = NULL,
+       .dri_library_name = radeon_ms_driver_dri_library_name,
+       .device_is_agp = NULL,
+       .irq_handler = radeon_ms_irq_handler,
+       .irq_preinstall = radeon_ms_irq_preinstall,
+       .irq_postinstall = radeon_ms_irq_postinstall,
+       .irq_uninstall = radeon_ms_irq_uninstall,
+       .reclaim_buffers = drm_core_reclaim_buffers,
+       .reclaim_buffers_locked = NULL,
+       .reclaim_buffers_idlelocked = NULL,
+       .get_map_ofs = drm_core_get_map_ofs,
+       .get_reg_ofs = drm_core_get_reg_ofs,
+       .set_version = NULL,
+       .fb_probe = radeonfb_probe,
+       .fb_remove = radeonfb_remove,
+       .fence_driver = &radeon_ms_fence_driver,
+       .bo_driver = &radeon_ms_bo_driver,
+       .major = DRIVER_MAJOR,
+       .minor = DRIVER_MINOR,
+       .patchlevel = DRIVER_PATCHLEVEL,
+       .name = DRIVER_NAME,
+       .desc = DRIVER_DESC,
+       .date = DRIVER_DATE,
+       .driver_features =
+           DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
+           DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED,
+       .dev_priv_size = 0, 
+       .ioctls = radeon_ms_ioctls,
+       .num_ioctls = 0,
+       .fops = {
+               .owner = THIS_MODULE,
+               .open = drm_open,
+               .release = drm_release,
+               .ioctl = drm_ioctl,
+               .mmap = drm_mmap,
+               .poll = drm_poll,
+               .fasync = drm_fasync,
+#if defined(CONFIG_COMPAT) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9)
+               .compat_ioctl = radeon_ms_compat_ioctl,
+#endif
+               },
+       .pci_driver = {
+               .name = DRIVER_NAME,
+               .id_table = pciidlist,
+               .probe = radeon_ms_driver_probe,
+               .remove = __devexit_p(drm_cleanup_pci),
+       },
+};
+
+static int radeon_ms_driver_probe(struct pci_dev *pdev,
+                                 const struct pci_device_id *ent)
+{
+       return drm_get_dev(pdev, ent, &driver);
+}
+
+static int radeon_ms_driver_dri_library_name(struct drm_device * dev,
+                                            char * buf)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       int ret;
+
+       switch (dev_priv->family) {
+       default:
+               ret = snprintf(buf, PAGE_SIZE, "\n");
+       }
+       return ret;
+}
+
+static void __exit radeon_ms_driver_exit(void)
+{
+       drm_exit(&driver);
+}
+
+static int __init radeon_ms_driver_init(void)
+{
+       driver.num_ioctls = radeon_ms_num_ioctls;
+       return drm_init(&driver, pciidlist);
+}
+
+module_init(radeon_ms_driver_init);
+module_exit(radeon_ms_driver_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL and additional rights");
diff --git a/linux-core/radeon_ms_drv.h b/linux-core/radeon_ms_drv.h
new file mode 100644 (file)
index 0000000..529f9c4
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2007 Dave Airlie
+ * Copyright 2007 Alex Deucher
+ * Copyright 2007 Michel Dänzer
+ * Copyright 2007 Roland Scheidegger
+ * Copyright 2007 Vladimir Dergachev
+ * Copyright 2007 Nicolai Haehnle
+ * Copyright 2007 Aapo Tahkola
+ * Copyright 2007 Ben Skeggs
+ * Copyright 2007 Jérôme Glisse
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ */
+/*
+ * Authors:
+ *    Jérôme Glisse <glisse@freedesktop.org>
+ */
+#ifndef __RADEON_MS_DRV_H__
+#define __RADEON_MS_DRV_H__
+
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+#include "drm.h"
+#include "drmP.h"
+
+#endif
diff --git a/linux-core/radeon_ms_exec.c b/linux-core/radeon_ms_exec.c
new file mode 120000 (symlink)
index 0000000..cb397fb
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_exec.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_family.c b/linux-core/radeon_ms_family.c
new file mode 120000 (symlink)
index 0000000..1f12e09
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_family.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_fb.c b/linux-core/radeon_ms_fb.c
new file mode 100644 (file)
index 0000000..d7fb39e
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * Copyright Â© 2007 David Airlie
+ * Copyright Â© 2007 Jerome Glisse
+ *
+ * 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.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "radeon_ms.h"
+
+struct radeonfb_par {
+       struct drm_device       *dev;
+       struct drm_crtc         *crtc;
+       struct drm_display_mode *fb_mode;
+};
+
+static int radeonfb_setcolreg(unsigned regno, unsigned red,
+                              unsigned green, unsigned blue,
+                              unsigned transp, struct fb_info *info)
+{
+       struct radeonfb_par *par = info->par;
+       struct drm_framebuffer *fb = par->crtc->fb;
+       struct drm_crtc *crtc = par->crtc;
+
+       if (regno > 255) {
+               return 1;
+       }
+       if (crtc->funcs->gamma_set) {
+               crtc->funcs->gamma_set(crtc, red, green, blue, regno);
+       }
+       if (regno < 16) {
+               switch (fb->depth) {
+               case 15:
+                       fb->pseudo_palette[regno] = ((red & 0xf800) >>  1) |
+                               ((green & 0xf800) >>  6) |
+                               ((blue & 0xf800) >> 11);
+                       break;
+               case 16:
+                       fb->pseudo_palette[regno] = (red & 0xf800) |
+                               ((green & 0xfc00) >>  5) |
+                               ((blue  & 0xf800) >> 11);
+                       break;
+               case 24:
+               case 32:
+                       fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
+                               (green & 0xff00) |
+                               ((blue  & 0xff00) >> 8);
+                       break;
+               }
+       }
+       return 0;
+}
+
+static int radeonfb_check_var(struct fb_var_screeninfo *var,
+                              struct fb_info *info)
+{
+        struct radeonfb_par *par = info->par;
+       struct drm_framebuffer *fb = par->crtc->fb;
+
+        if (!var->pixclock)
+                return -EINVAL;
+
+        /* Need to resize the fb object !!! */
+        if (var->xres > fb->width || var->yres > fb->height) {
+                DRM_ERROR("Requested width/height is greater than "
+                         "current fb object %dx%d > %dx%d\n",
+                         var->xres, var->yres, fb->width, fb->height);
+                DRM_ERROR("Need resizing code.\n");
+                return -EINVAL;
+        }
+
+        switch (var->bits_per_pixel) {
+        case 16:
+               if (var->green.length == 5) {
+                       var->red.offset = 10;
+                       var->green.offset = 5;
+                       var->blue.offset = 0;
+                       var->red.length = 5;
+                       var->green.length = 5;
+                       var->blue.length = 5;
+                       var->transp.length = 0;
+                       var->transp.offset = 0;
+               } else {
+                       var->red.offset = 11;
+                       var->green.offset = 6;
+                       var->blue.offset = 0;
+                       var->red.length = 5;
+                       var->green.length = 6;
+                       var->blue.length = 5;
+                       var->transp.length = 0;
+                       var->transp.offset = 0;
+               }
+                break;
+       case 32:
+                if (var->transp.length) {
+                       var->red.offset = 16;
+                       var->green.offset = 8;
+                       var->blue.offset = 0;
+                       var->red.length = 8;
+                       var->green.length = 8;
+                       var->blue.length = 8;
+                       var->transp.length = 8;
+                       var->transp.offset = 24;
+               } else {
+                       var->red.offset = 16;
+                       var->green.offset = 8;
+                       var->blue.offset = 0;
+                       var->red.length = 8;
+                       var->green.length = 8;
+                       var->blue.length = 8;
+                       var->transp.length = 0;
+                       var->transp.offset = 0;
+               }
+               break;
+        default:
+               return -EINVAL; 
+        }
+       return 0;
+}
+
+static bool radeonfb_mode_equal(struct drm_display_mode *mode1,
+                               struct drm_display_mode *mode2)
+{
+       if (mode1->hdisplay == mode2->hdisplay &&
+           mode1->hsync_start == mode2->hsync_start &&
+           mode1->hsync_end == mode2->hsync_end &&
+           mode1->htotal == mode2->htotal &&
+           mode1->hskew == mode2->hskew &&
+           mode1->vdisplay == mode2->vdisplay &&
+           mode1->vsync_start == mode2->vsync_start &&
+           mode1->vsync_end == mode2->vsync_end &&
+           mode1->vtotal == mode2->vtotal &&
+           mode1->vscan == mode2->vscan &&
+           mode1->flags == mode2->flags) {
+               /* FIXME: what about adding a margin for clock ? */
+               if (mode1->clock == mode2->clock)
+                       return true;
+               return false;
+       }
+       
+       return false;
+}
+
+static int radeonfb_set_par(struct fb_info *info)
+{
+       struct radeonfb_par *par = info->par;
+       struct drm_framebuffer *fb = par->crtc->fb;
+       struct drm_device *dev = par->dev;
+        struct drm_display_mode *drm_mode, *search_mode;
+        struct drm_output *output;
+        struct fb_var_screeninfo *var = &info->var;
+       int found = 0;
+
+        switch (var->bits_per_pixel) {
+        case 16:
+               fb->depth = (var->green.length == 6) ? 16 : 15;
+               break;
+        case 32:
+               fb->depth = (var->transp.length > 0) ? 32 : 24;
+               break;
+       default:
+               return -EINVAL; 
+       }
+       fb->bits_per_pixel = var->bits_per_pixel;
+
+       info->fix.line_length = fb->pitch;
+       info->fix.smem_len = info->fix.line_length * fb->height;
+       info->fix.visual = FB_VISUAL_TRUECOLOR;
+       info->screen_size = info->fix.smem_len; /* ??? */
+
+        /* Should we walk the output's modelist or just create our own ???
+         * For now, we create and destroy a mode based on the incoming 
+         * parameters. But there's commented out code below which scans 
+         * the output list too.
+         */
+       drm_mode = drm_mode_create(dev);
+       drm_mode->hdisplay = var->xres;
+       drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin;
+       drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len;
+       drm_mode->htotal = drm_mode->hsync_end + var->left_margin;
+       drm_mode->vdisplay = var->yres;
+       drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin;
+       drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len;
+       drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin;
+       drm_mode->clock = PICOS2KHZ(var->pixclock);
+       drm_mode->vrefresh = drm_mode_vrefresh(drm_mode);
+       drm_mode_set_name(drm_mode);
+       drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V);
+
+        list_for_each_entry(output, &dev->mode_config.output_list, head) {
+                if (output->crtc == par->crtc)
+                        break;
+        }
+
+       drm_mode_debug_printmodeline(dev, drm_mode);    
+        list_for_each_entry(search_mode, &output->modes, head) {
+               drm_mode_debug_printmodeline(dev, search_mode);
+               if (radeonfb_mode_equal(drm_mode, search_mode)) {
+                       drm_mode_destroy(dev, drm_mode);
+                       drm_mode = search_mode;
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found) {
+               if (par->fb_mode) {
+                       drm_mode_detachmode_crtc(dev, par->fb_mode);
+               }
+               par->fb_mode = drm_mode;
+               drm_mode_debug_printmodeline(dev, drm_mode);
+               /* attach mode */
+               drm_mode_attachmode_crtc(dev, par->crtc, par->fb_mode);
+       }
+
+       if (par->crtc->enabled) {
+               if (!drm_mode_equal(&par->crtc->mode, drm_mode)) {
+                       if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0)) {
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static struct fb_ops radeonfb_ops = {
+       .owner = THIS_MODULE,
+       //      .fb_open = radeonfb_open,
+       //      .fb_read = radeonfb_read,
+       //      .fb_write = radeonfb_write,
+       //      .fb_release = radeonfb_release,
+       //      .fb_ioctl = radeonfb_ioctl,
+       .fb_check_var = radeonfb_check_var,
+       .fb_set_par = radeonfb_set_par,
+       .fb_setcolreg = radeonfb_setcolreg,
+       .fb_fillrect = cfb_fillrect,
+       .fb_copyarea = cfb_copyarea,
+       .fb_imageblit = cfb_imageblit,
+};
+
+int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc)
+{
+       struct fb_info *info;
+       struct radeonfb_par *par;
+       struct device *device = &dev->pdev->dev; 
+       struct drm_framebuffer *fb;
+       struct drm_display_mode *mode = crtc->desired_mode;
+       int ret;
+
+       info = framebuffer_alloc(sizeof(struct radeonfb_par), device);
+       if (!info){
+               DRM_INFO("[radeon_ms] framebuffer_alloc failed\n");
+               return -EINVAL;
+       }
+
+       fb = drm_framebuffer_create(dev);
+       if (!fb) {
+               framebuffer_release(info);
+               DRM_ERROR("[radeon_ms] failed to allocate fb.\n");
+               return -EINVAL;
+       }
+       crtc->fb = fb;
+
+       fb->width = crtc->desired_mode->hdisplay;
+       fb->height = crtc->desired_mode->vdisplay;
+       fb->bits_per_pixel = 32;
+       fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8);
+       fb->depth = 24;
+       /* one page alignment should be fine for constraint (micro|macro tiling,
+        * bit depth, color buffer offset, ...) */
+       ret = drm_buffer_object_create(dev, fb->width * fb->height * 4, 
+                                      drm_bo_type_kernel,
+                                      DRM_BO_FLAG_READ |
+                                      DRM_BO_FLAG_WRITE |
+                                      DRM_BO_FLAG_NO_EVICT |
+                                      DRM_BO_FLAG_MEM_VRAM,
+                                      DRM_BO_HINT_DONT_FENCE,
+                                      1,
+                                      0,
+                                      &fb->bo);
+       if (ret || fb->bo == NULL) {
+               DRM_ERROR("[radeon_ms] failed to allocate framebuffer\n");
+               drm_framebuffer_destroy(fb);
+               framebuffer_release(info);
+               return -EINVAL;
+       }
+
+       DRM_INFO("[radeon_ms] framebuffer %dx%d at 0x%08lX\n",
+                fb->width, fb->height, fb->bo->offset);
+
+       fb->fbdev = info;
+       par = info->par;
+       par->dev = dev;
+       par->crtc = crtc;
+       info->fbops = &radeonfb_ops;
+       strcpy(info->fix.id, "radeonfb");
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+       info->fix.visual = FB_VISUAL_TRUECOLOR;
+       info->fix.type_aux = 0;
+       info->fix.xpanstep = 8;
+       info->fix.ypanstep = 1;
+       info->fix.ywrapstep = 0;
+       info->fix.accel = FB_ACCEL_ATI_RADEON;
+       info->fix.type_aux = 0;
+       info->fix.mmio_start = 0;
+       info->fix.mmio_len = 0;
+       info->fix.line_length = fb->pitch;
+       info->fix.smem_start = fb->bo->offset + dev->mode_config.fb_base;
+       info->fix.smem_len = info->fix.line_length * fb->height;
+       info->flags = FBINFO_DEFAULT;
+       DRM_INFO("[radeon_ms] fb physical start : 0x%lX\n", info->fix.smem_start);
+       DRM_INFO("[radeon_ms] fb physical size  : %d\n", info->fix.smem_len);
+
+       ret = drm_mem_reg_ioremap(dev, &fb->bo->mem, &fb->virtual_base);
+       if (ret) {
+               DRM_ERROR("error mapping fb: %d\n", ret);
+       }
+
+       info->screen_base = fb->virtual_base;
+       info->screen_size = info->fix.smem_len; /* FIXME */
+       info->pseudo_palette = fb->pseudo_palette;
+       info->var.xres_virtual = fb->width;
+       info->var.yres_virtual = fb->height;
+       info->var.bits_per_pixel = fb->bits_per_pixel;
+       info->var.xoffset = 0;
+       info->var.yoffset = 0;
+       info->var.activate = FB_ACTIVATE_NOW;
+       info->var.height = -1;
+       info->var.width = -1;
+       info->var.vmode = FB_VMODE_NONINTERLACED;
+
+       info->var.xres = mode->hdisplay;
+       info->var.right_margin = mode->hsync_start - mode->hdisplay;
+       info->var.hsync_len = mode->hsync_end - mode->hsync_start;
+       info->var.left_margin = mode->htotal - mode->hsync_end;
+       info->var.yres = mode->vdisplay;
+       info->var.lower_margin = mode->vsync_start - mode->vdisplay;
+       info->var.vsync_len = mode->vsync_end - mode->vsync_start;
+       info->var.upper_margin = mode->vtotal - mode->vsync_end;
+       info->var.pixclock = 10000000 / mode->htotal * 1000 /
+               mode->vtotal * 100;
+       /* avoid overflow */
+       info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
+
+       info->pixmap.size = 64*1024;
+       info->pixmap.buf_align = 8;
+       info->pixmap.access_align = 32;
+       info->pixmap.flags = FB_PIXMAP_SYSTEM;
+       info->pixmap.scan_align = 1;
+
+       DRM_DEBUG("fb depth is %d\n", fb->depth);
+       DRM_DEBUG("   pitch is %d\n", fb->pitch);
+       switch(fb->depth) {
+       case 15:
+                info->var.red.offset = 10;
+               info->var.green.offset = 5;
+               info->var.blue.offset = 0;
+               info->var.red.length = info->var.green.length =
+                       info->var.blue.length = 5;
+               info->var.transp.offset = 15;
+                info->var.transp.length = 1;
+                break;
+       case 16:
+                info->var.red.offset = 11;
+                info->var.green.offset = 5;
+                info->var.blue.offset = 0;
+                info->var.red.length = 5;
+                info->var.green.length = 6;
+                info->var.blue.length = 5;
+                info->var.transp.offset = 0;
+               break;
+       case 24:
+                info->var.red.offset = 16;
+                info->var.green.offset = 8;
+                info->var.blue.offset = 0;
+                info->var.red.length = info->var.green.length =
+                        info->var.blue.length = 8;
+                info->var.transp.offset = 0;
+                info->var.transp.length = 0;
+                break;
+       case 32:
+               info->var.red.offset = 16;
+               info->var.green.offset = 8;
+               info->var.blue.offset = 0;
+               info->var.red.length = info->var.green.length =
+                       info->var.blue.length = 8;
+               info->var.transp.offset = 24;
+               info->var.transp.length = 8;
+               break;
+       default:
+               DRM_ERROR("only support 15, 16, 24 or 32bits per pixel "
+                         "got %d\n", fb->depth);
+               return -EINVAL;
+               break;
+       }
+
+       if (register_framebuffer(info) < 0) {
+               return -EINVAL;
+       }
+
+       DRM_INFO("[radeon_ms] fb%d: %s frame buffer device\n", info->node,
+                info->fix.id);
+       return 0;
+}
+EXPORT_SYMBOL(radeonfb_probe);
+
+int radeonfb_remove(struct drm_device *dev, struct drm_crtc *crtc)
+{
+       struct drm_framebuffer *fb = crtc->fb;
+       struct fb_info *info = fb->fbdev;
+       
+       if (info) {
+               unregister_framebuffer(info);
+               framebuffer_release(info);
+               drm_mem_reg_iounmap(dev, &fb->bo->mem, fb->virtual_base);
+               drm_bo_usage_deref_unlocked(&fb->bo);
+               drm_framebuffer_destroy(fb);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(radeonfb_remove);
+MODULE_LICENSE("GPL");
diff --git a/linux-core/radeon_ms_fence.c b/linux-core/radeon_ms_fence.c
new file mode 120000 (symlink)
index 0000000..383cc07
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_fence.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_gpu.c b/linux-core/radeon_ms_gpu.c
new file mode 120000 (symlink)
index 0000000..fa5e05b
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_gpu.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_i2c.c b/linux-core/radeon_ms_i2c.c
new file mode 120000 (symlink)
index 0000000..1863e6d
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_i2c.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_irq.c b/linux-core/radeon_ms_irq.c
new file mode 120000 (symlink)
index 0000000..c4e60ba
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_irq.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_output.c b/linux-core/radeon_ms_output.c
new file mode 120000 (symlink)
index 0000000..6a38b67
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_output.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_properties.c b/linux-core/radeon_ms_properties.c
new file mode 120000 (symlink)
index 0000000..e2e0dc0
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_properties.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_properties.h b/linux-core/radeon_ms_properties.h
new file mode 120000 (symlink)
index 0000000..59783e8
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_properties.h
\ No newline at end of file
diff --git a/linux-core/radeon_ms_reg.h b/linux-core/radeon_ms_reg.h
new file mode 120000 (symlink)
index 0000000..24b01b4
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_reg.h
\ No newline at end of file
diff --git a/linux-core/radeon_ms_rom.c b/linux-core/radeon_ms_rom.c
new file mode 120000 (symlink)
index 0000000..80f5f60
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_rom.c
\ No newline at end of file
diff --git a/linux-core/radeon_ms_rom.h b/linux-core/radeon_ms_rom.h
new file mode 120000 (symlink)
index 0000000..f20e42b
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_rom.h
\ No newline at end of file
diff --git a/linux-core/radeon_ms_state.c b/linux-core/radeon_ms_state.c
new file mode 120000 (symlink)
index 0000000..2d2e2ef
--- /dev/null
@@ -0,0 +1 @@
+../shared-core/radeon_ms_state.c
\ No newline at end of file
index 3a680a3..20df477 100644 (file)
@@ -63,7 +63,7 @@ static void via_fence_poll(struct drm_device *dev, uint32_t class,
 
 
                if (!dev_priv->have_idlelock) {
-                       drm_idlelock_take(&dev->lock);
+                       drm_idlelock_take(&dev->primary->master->lock);
                        dev_priv->have_idlelock = 1;
                }
 
index 5981dcb..303a84b 100644 (file)
@@ -960,6 +960,175 @@ struct drm_mm_info_arg {
        uint64_t p_size;
 };
 
+
+/*
+ * Drm mode setting
+ */
+#define DRM_DISPLAY_INFO_LEN 32
+#define DRM_OUTPUT_NAME_LEN 32
+#define DRM_DISPLAY_MODE_LEN 32
+#define DRM_PROP_NAME_LEN 32
+
+#define DRM_MODE_TYPE_BUILTIN  (1<<0)
+#define DRM_MODE_TYPE_CLOCK_C  ((1<<1) | DRM_MODE_TYPE_BUILTIN)
+#define DRM_MODE_TYPE_CRTC_C   ((1<<2) | DRM_MODE_TYPE_BUILTIN)
+#define DRM_MODE_TYPE_PREFERRED        (1<<3)
+#define DRM_MODE_TYPE_DEFAULT  (1<<4)
+#define DRM_MODE_TYPE_USERDEF  (1<<5)
+#define DRM_MODE_TYPE_DRIVER   (1<<6)
+
+struct drm_mode_modeinfo {
+       unsigned int clock;
+       unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew;
+       unsigned short vdisplay, vsync_start, vsync_end, vtotal, vscan;
+
+       unsigned int vrefresh; /* vertical refresh * 1000 */
+
+       unsigned int flags;
+       unsigned int type;
+       char name[DRM_DISPLAY_MODE_LEN];
+};
+
+struct drm_mode_card_res {
+       uint64_t fb_id_ptr;
+       uint64_t crtc_id_ptr;
+       uint64_t output_id_ptr;
+       int count_fbs;
+       int count_crtcs;
+       int count_outputs;
+       int min_width, max_width;
+       int min_height, max_height;
+};
+
+struct drm_mode_crtc {
+       uint64_t set_outputs_ptr;
+
+       unsigned int crtc_id; /**< Id */
+       unsigned int fb_id; /**< Id of framebuffer */
+
+       int x, y; /**< Position on the frameuffer */
+
+       int count_outputs;
+       unsigned int outputs; /**< Outputs that are connected */
+
+       int count_possibles;
+       unsigned int possibles; /**< Outputs that can be connected */
+       int gamma_size;
+       int mode_valid;
+       struct drm_mode_modeinfo mode;
+};
+
+#define DRM_MODE_OUTPUT_NONE 0
+#define DRM_MODE_OUTPUT_DAC  1
+#define DRM_MODE_OUTPUT_TMDS 2
+#define DRM_MODE_OUTPUT_LVDS 3
+#define DRM_MODE_OUTPUT_TVDAC 4
+
+struct drm_mode_get_output {
+
+       uint64_t modes_ptr;
+       uint64_t props_ptr;
+       uint64_t prop_values_ptr;
+
+       int count_modes;
+       int count_props;
+       unsigned int output; /**< Id */
+       unsigned int crtc; /**< Id of crtc */
+       unsigned int output_type;
+       unsigned int output_type_id;
+
+       unsigned int connection;
+       unsigned int mm_width, mm_height; /**< HxW in millimeters */
+       unsigned int subpixel;
+       int count_crtcs;
+       int count_clones;
+       unsigned int crtcs; /**< possible crtc to connect to */
+       unsigned int clones; /**< list of clones */
+};
+
+#define DRM_MODE_PROP_PENDING (1<<0)
+#define DRM_MODE_PROP_RANGE (1<<1)
+#define DRM_MODE_PROP_IMMUTABLE (1<<2)
+#define DRM_MODE_PROP_ENUM (1<<3) // enumerated type with text strings
+#define DRM_MODE_PROP_BLOB (1<<4)
+
+struct drm_mode_property_enum {
+       uint64_t value;
+       unsigned char name[DRM_PROP_NAME_LEN];
+};
+
+struct drm_mode_get_property {
+       uint64_t values_ptr; /* values and blob lengths */
+       uint64_t enum_blob_ptr; /* enum and blob id ptrs */
+
+       unsigned int prop_id;
+       unsigned int flags;
+       unsigned char name[DRM_PROP_NAME_LEN];
+
+       int count_values;
+       int count_enum_blobs;
+};
+
+struct drm_mode_output_set_property {
+       uint64_t value;
+       unsigned int prop_id;
+       unsigned int output_id;
+};
+
+struct drm_mode_get_blob {
+       uint32_t blob_id;
+       uint32_t length;
+       uint64_t data;
+};
+
+struct drm_mode_fb_cmd {
+        unsigned int buffer_id;
+        unsigned int width, height;
+        unsigned int pitch;
+        unsigned int bpp;
+        unsigned int handle;
+       unsigned int depth;
+};
+
+struct drm_mode_mode_cmd {
+       unsigned int output_id;
+       struct drm_mode_modeinfo mode;
+};
+
+#define DRM_MODE_CURSOR_BO   0x01
+#define DRM_MODE_CURSOR_MOVE 0x02
+
+/*
+ * depending on the value in flags diffrent members are used.
+ *
+ * CURSOR_BO uses
+ *    crtc
+ *    width
+ *    height
+ *    handle - if 0 turns the cursor of
+ *
+ * CURSOR_MOVE uses
+ *    crtc
+ *    x
+ *    y
+ */
+struct drm_mode_cursor {
+       unsigned int flags;
+       unsigned int crtc;
+       int x;
+       int y;
+       uint32_t width;
+       uint32_t height;
+       unsigned int handle;
+};
+
+/*
+ * oh so ugly hotplug
+ */
+struct drm_mode_hotplug {
+       uint32_t counter;
+};
+
 /**
  * \name Ioctls Definitions
  */
@@ -1053,6 +1222,23 @@ struct drm_mm_info_arg {
 #define DRM_IOCTL_BO_VERSION          DRM_IOR(0xd6, struct drm_bo_version_arg)
 #define DRM_IOCTL_MM_INFO               DRM_IOWR(0xd7, struct drm_mm_info_arg)
 
+#define DRM_IOCTL_MODE_GETRESOURCES     DRM_IOWR(0xA0, struct drm_mode_card_res)
+#define DRM_IOCTL_MODE_GETCRTC          DRM_IOWR(0xA1, struct drm_mode_crtc)
+#define DRM_IOCTL_MODE_GETOUTPUT        DRM_IOWR(0xA2, struct drm_mode_get_output)
+#define DRM_IOCTL_MODE_SETCRTC          DRM_IOWR(0xA3, struct drm_mode_crtc)
+#define DRM_IOCTL_MODE_ADDFB            DRM_IOWR(0xA4, struct drm_mode_fb_cmd)
+#define DRM_IOCTL_MODE_RMFB             DRM_IOWR(0xA5, unsigned int)
+#define DRM_IOCTL_MODE_GETFB            DRM_IOWR(0xA6, struct drm_mode_fb_cmd)
+
+#define DRM_IOCTL_MODE_SETPROPERTY     DRM_IOWR(0xA7, struct drm_mode_output_set_property)
+#define DRM_IOCTL_MODE_GETPROPBLOB     DRM_IOWR(0xA8, struct drm_mode_get_blob)
+#define DRM_IOCTL_MODE_ATTACHMODE      DRM_IOWR(0xA9, struct drm_mode_mode_cmd)
+#define DRM_IOCTL_MODE_DETACHMODE      DRM_IOWR(0xAA, struct drm_mode_mode_cmd)
+
+#define DRM_IOCTL_MODE_GETPROPERTY     DRM_IOWR(0xAB, struct drm_mode_get_property)
+#define DRM_IOCTL_MODE_CURSOR          DRM_IOWR(0xAC, struct drm_mode_cursor)
+#define DRM_IOCTL_MODE_HOTPLUG         DRM_IOWR(0xAD, struct drm_mode_hotplug)
+
 /*@}*/
 
 /**
index 63b5cd5..c895d7f 100644 (file)
@@ -1,3 +1,7 @@
+[radeon_ms]
+0x1002 0x4150 CHIP_RV350|RADEON_AGP "ATI Radeon RV350 9600"
+0x1002 0x5b63 CHIP_RV370|RADEON_PCIE "ATI Radeon RV370 X550"
+
 [radeon]
 0x1002 0x3150 CHIP_RV380|RADEON_IS_MOBILITY "ATI Radeon Mobility X600 M24"
 0x1002 0x3152 CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP "ATI Radeon Mobility X300 M24"
index 7d247f9..8237e14 100644 (file)
@@ -38,8 +38,8 @@
  */
 int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_ring_buffer *ring = &(dev_priv->ring);
        u32 last_head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
        int i;
 
@@ -63,8 +63,13 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
 
 void i915_kernel_lost_context(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_ring_buffer *ring = &(dev_priv->ring);
+
+       /* we should never lose context on the ring with modesetting 
+        * as we don't expose it to userspace */
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               return;
 
        ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
        ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
@@ -73,9 +78,13 @@ void i915_kernel_lost_context(struct drm_device * dev)
                ring->space += ring->Size;
 }
 
-static int i915_dma_cleanup(struct drm_device * dev)
+int i915_dma_cleanup(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               return 0;
+
        /* Make sure interrupts are disabled here because the uninstall ioctl
         * may not have been called from userspace and after dev_private
         * is freed, it's too late.
@@ -83,25 +92,27 @@ static int i915_dma_cleanup(struct drm_device * dev)
        if (dev->irq)
                drm_irq_uninstall(dev);
 
-       if (dev_priv->ring.virtual_start) {
-               drm_core_ioremapfree(&dev_priv->ring.map, dev);
-               dev_priv->ring.virtual_start = 0;
-               dev_priv->ring.map.handle = 0;
-               dev_priv->ring.map.size = 0;
-       }
+        if (dev_priv->ring.virtual_start) {
+                drm_core_ioremapfree(&dev_priv->ring.map, dev);
+                dev_priv->ring.virtual_start = 0;
+                dev_priv->ring.map.handle = 0;
+                dev_priv->ring.map.size = 0;
+               dev_priv->ring.Size = 0;
+        }
 
-       if (dev_priv->status_page_dmah) {
-               drm_pci_free(dev, dev_priv->status_page_dmah);
-               dev_priv->status_page_dmah = NULL;
-               /* Need to rewrite hardware status page */
-               I915_WRITE(0x02080, 0x1ffff000);
-       }
+        if (dev_priv->status_page_dmah) {
+                drm_pci_free(dev, dev_priv->status_page_dmah);
+                dev_priv->status_page_dmah = NULL;
+                /* Need to rewrite hardware status page */
+                I915_WRITE(0x02080, 0x1ffff000);
+        }
+
+        if (dev_priv->status_gfx_addr) {
+                dev_priv->status_gfx_addr = 0;
+                drm_core_ioremapfree(&dev_priv->hws_map, dev);
+                I915_WRITE(0x02080, 0x1ffff000);
+        }
 
-       if (dev_priv->status_gfx_addr) {
-               dev_priv->status_gfx_addr = 0;
-               drm_core_ioremapfree(&dev_priv->hws_map, dev);
-               I915_WRITE(0x02080, 0x1ffff000);
-       }
 
        return 0;
 }
@@ -122,7 +133,7 @@ setup_dri2_sarea(struct drm_device * dev,
                 struct drm_file *file_priv,
                 drm_i915_init_t * init)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
        unsigned int *p, *end, *next;
 
@@ -150,8 +161,8 @@ setup_dri2_sarea(struct drm_device * dev,
        while (p < end && DRI2_SAREA_BLOCK_TYPE(*p) != DRI2_SAREA_BLOCK_END) {
                switch (DRI2_SAREA_BLOCK_TYPE(*p)) {
                case DRI2_SAREA_BLOCK_LOCK:
-                       dev->lock.hw_lock = (void *) (p + 1);
-                       dev->sigdata.lock = dev->lock.hw_lock;
+                       dev->primary->master->lock.hw_lock = (void *) (p + 1);
+                       dev->sigdata.lock = dev->primary->master->lock.hw_lock;
                        break;
                }
                next = DRI2_SAREA_BLOCK_NEXT(p);
@@ -171,63 +182,50 @@ static int i915_initialize(struct drm_device * dev,
                           struct drm_file *file_priv,
                           drm_i915_init_t * init)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       int ret;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
 
-       dev_priv->sarea = drm_getsarea(dev);
-       if (!dev_priv->sarea) {
-               DRM_ERROR("can not find sarea!\n");
-               i915_dma_cleanup(dev);
-               return -EINVAL;
+       if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
+               if (init->mmio_offset != 0)
+                       dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
+               if (!dev_priv->mmio_map) {
+                       i915_dma_cleanup(dev);
+                       DRM_ERROR("can not find mmio map!\n");
+                       return -EINVAL;
+               }
        }
 
-       if (init->mmio_offset != 0)
-               dev_priv->mmio_map = drm_core_findmap(dev, init->mmio_offset);
-       if (!dev_priv->mmio_map) {
-               i915_dma_cleanup(dev);
-               DRM_ERROR("can not find mmio map!\n");
-               return -EINVAL;
-       }
 
 #ifdef I915_HAVE_BUFFER
        dev_priv->max_validate_buffers = I915_MAX_VALIDATE_BUFFERS;
 #endif
 
-       if (init->sarea_priv_offset)
-               dev_priv->sarea_priv = (drm_i915_sarea_t *)
-                       ((u8 *) dev_priv->sarea->handle +
-                        init->sarea_priv_offset);
-       else {
-               /* No sarea_priv for you! */
-               dev_priv->sarea_priv = NULL;
-       }
-
-       dev_priv->ring.Start = init->ring_start;
-       dev_priv->ring.End = init->ring_end;
-       dev_priv->ring.Size = init->ring_size;
-       dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
-
-       dev_priv->ring.map.offset = init->ring_start;
-       dev_priv->ring.map.size = init->ring_size;
-       dev_priv->ring.map.type = 0;
-       dev_priv->ring.map.flags = 0;
-       dev_priv->ring.map.mtrr = 0;
-
-       drm_core_ioremap(&dev_priv->ring.map, dev);
-
-       if (dev_priv->ring.map.handle == NULL) {
-               i915_dma_cleanup(dev);
-               DRM_ERROR("can not ioremap virtual address for"
-                         " ring buffer\n");
-               return -ENOMEM;
+       if (!dev_priv->ring.Size) {
+               dev_priv->ring.Start = init->ring_start;
+               dev_priv->ring.End = init->ring_end;
+               dev_priv->ring.Size = init->ring_size;
+               dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+               
+               dev_priv->ring.map.offset = init->ring_start;
+               dev_priv->ring.map.size = init->ring_size;
+               dev_priv->ring.map.type = 0;
+               dev_priv->ring.map.flags = 0;
+               dev_priv->ring.map.mtrr = 0;
+               
+               drm_core_ioremap(&dev_priv->ring.map, dev);
+               
+               if (dev_priv->ring.map.handle == NULL) {
+                       i915_dma_cleanup(dev);
+                       DRM_ERROR("can not ioremap virtual address for"
+                                 " ring buffer\n");
+                       return -ENOMEM;
+               }
+               dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
        }
 
-       dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
 
        dev_priv->cpp = init->cpp;
-
-       if (dev_priv->sarea_priv)
-               dev_priv->sarea_priv->pf_current_page = 0;
+       master_priv->sarea_priv->pf_current_page = 0;
 
        /* We are using separate values as placeholders for mechanisms for
         * private backbuffer/depthbuffer usage.
@@ -267,28 +265,25 @@ static int i915_initialize(struct drm_device * dev,
 #endif
 
        if (init->func == I915_INIT_DMA2) {
-               ret = setup_dri2_sarea(dev, file_priv, init);
+               int ret = setup_dri2_sarea(dev, file_priv, init);
                if (ret) {
                        i915_dma_cleanup(dev);
                        DRM_ERROR("could not set up dri2 sarea\n");
                        return ret;
                }
        }
-               
 
        return 0;
 }
 
 static int i915_dma_resume(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
 
        DRM_DEBUG("\n");
 
-       if (!dev_priv->sarea) {
-               DRM_ERROR("can not find sarea!\n");
-               return -EINVAL;
-       }
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               return 0;
 
        if (!dev_priv->mmio_map) {
                DRM_ERROR("can not find mmio map!\n");
@@ -320,7 +315,7 @@ static int i915_dma_resume(struct drm_device * dev)
 static int i915_dma_init(struct drm_device *dev, void *data,
                         struct drm_file *file_priv)
 {
-       drm_i915_init_t *init = data;
+       struct drm_i915_init *init = data;
        int retcode = 0;
 
        switch (init->func) {
@@ -421,7 +416,7 @@ static int validate_cmd(int cmd)
 static int i915_emit_cmds(struct drm_device *dev, int __user *buffer,
                          int dwords)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
        RING_LOCALS;
 
@@ -462,7 +457,7 @@ static int i915_emit_box(struct drm_device * dev,
                         struct drm_clip_rect __user * boxes,
                         int i, int DR1, int DR4)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_clip_rect box;
        RING_LOCALS;
 
@@ -503,7 +498,8 @@ static int i915_emit_box(struct drm_device * dev,
 
 void i915_emit_breadcrumb(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
        RING_LOCALS;
 
        if (++dev_priv->counter > BREADCRUMB_MASK) {
@@ -511,8 +507,7 @@ void i915_emit_breadcrumb(struct drm_device *dev)
                 DRM_DEBUG("Breadcrumb counter wrapped around\n");
        }
 
-       if (dev_priv->sarea_priv)
-               dev_priv->sarea_priv->last_enqueue = dev_priv->counter;
+       master_priv->sarea_priv->last_enqueue = dev_priv->counter;
 
        BEGIN_LP_RING(4);
        OUT_RING(CMD_STORE_DWORD_IDX);
@@ -525,7 +520,7 @@ void i915_emit_breadcrumb(struct drm_device *dev)
 
 int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t flush_cmd = CMD_MI_FLUSH;
        RING_LOCALS;
 
@@ -545,10 +540,10 @@ int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush)
 
 
 static int i915_dispatch_cmdbuffer(struct drm_device * dev,
-                                  drm_i915_cmdbuffer_t * cmd)
+                                  struct drm_i915_cmdbuffer * cmd)
 {
 #ifdef I915_HAVE_FENCE
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
 #endif
        int nbox = cmd->num_cliprects;
        int i = 0, count, ret;
@@ -586,7 +581,7 @@ static int i915_dispatch_cmdbuffer(struct drm_device * dev,
 static int i915_dispatch_batchbuffer(struct drm_device * dev,
                                     drm_i915_batchbuffer_t * batch)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_clip_rect __user *boxes = batch->cliprects;
        int nbox = batch->num_cliprects;
        int i = 0, count;
@@ -640,38 +635,39 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
 
 static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
        u32 num_pages, current_page, next_page, dspbase;
        int shift = 2 * plane, x, y;
        RING_LOCALS;
 
        /* Calculate display base offset */
-       num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2;
-       current_page = (dev_priv->sarea_priv->pf_current_page >> shift) & 0x3;
+       num_pages = master_priv->sarea_priv->third_handle ? 3 : 2;
+       current_page = (master_priv->sarea_priv->pf_current_page >> shift) & 0x3;
        next_page = (current_page + 1) % num_pages;
 
        switch (next_page) {
        default:
        case 0:
-               dspbase = dev_priv->sarea_priv->front_offset;
+               dspbase = master_priv->sarea_priv->front_offset;
                break;
        case 1:
-               dspbase = dev_priv->sarea_priv->back_offset;
+               dspbase = master_priv->sarea_priv->back_offset;
                break;
        case 2:
-               dspbase = dev_priv->sarea_priv->third_offset;
+               dspbase = master_priv->sarea_priv->third_offset;
                break;
        }
 
        if (plane == 0) {
-               x = dev_priv->sarea_priv->planeA_x;
-               y = dev_priv->sarea_priv->planeA_y;
+               x = master_priv->sarea_priv->planeA_x;
+               y = master_priv->sarea_priv->planeA_y;
        } else {
-               x = dev_priv->sarea_priv->planeB_x;
-               y = dev_priv->sarea_priv->planeB_y;
+               x = master_priv->sarea_priv->planeB_x;
+               y = master_priv->sarea_priv->planeB_y;
        }
 
-       dspbase += (y * dev_priv->sarea_priv->pitch + x) * dev_priv->cpp;
+       dspbase += (y * master_priv->sarea_priv->pitch + x) * dev_priv->cpp;
 
        DRM_DEBUG("plane=%d current_page=%d dspbase=0x%x\n", plane, current_page,
                  dspbase);
@@ -682,21 +678,22 @@ static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync)
                                       MI_WAIT_FOR_PLANE_A_FLIP)));
        OUT_RING(CMD_OP_DISPLAYBUFFER_INFO | (sync ? 0 : ASYNC_FLIP) |
                 (plane ? DISPLAY_PLANE_B : DISPLAY_PLANE_A));
-       OUT_RING(dev_priv->sarea_priv->pitch * dev_priv->cpp);
+       OUT_RING(master_priv->sarea_priv->pitch * dev_priv->cpp);
        OUT_RING(dspbase);
        ADVANCE_LP_RING();
 
-       dev_priv->sarea_priv->pf_current_page &= ~(0x3 << shift);
-       dev_priv->sarea_priv->pf_current_page |= next_page << shift;
+       master_priv->sarea_priv->pf_current_page &= ~(0x3 << shift);
+       master_priv->sarea_priv->pf_current_page |= next_page << shift;
 }
 
 void i915_dispatch_flip(struct drm_device * dev, int planes, int sync)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
        int i;
 
        DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n",
-                 planes, dev_priv->sarea_priv->pf_current_page);
+                 planes, master_priv->sarea_priv->pf_current_page);
 
        i915_emit_mi_flush(dev, MI_READ_FLUSH | MI_EXE_FLUSH);
 
@@ -713,7 +710,7 @@ void i915_dispatch_flip(struct drm_device * dev, int planes, int sync)
 
 static int i915_quiescent(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        i915_kernel_lost_context(dev);
        return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
@@ -731,9 +728,10 @@ static int i915_flush_ioctl(struct drm_device *dev, void *data,
 static int i915_batchbuffer(struct drm_device *dev, void *data,
                            struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
        drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
-           dev_priv->sarea_priv;
+           master_priv->sarea_priv;
        drm_i915_batchbuffer_t *batch = data;
        int ret;
 
@@ -761,10 +759,11 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
 static int i915_cmdbuffer(struct drm_device *dev, void *data,
                          struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
-           dev_priv->sarea_priv;
-       drm_i915_cmdbuffer_t *cmdbuf = data;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
+       struct drm_i915_sarea *sarea_priv = (struct drm_i915_sarea *)
+               master_priv->sarea_priv;
+       struct drm_i915_cmdbuffer *cmdbuf = data;
        int ret;
 
        DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
@@ -1264,9 +1263,10 @@ void i915_fence_or_sync(struct drm_file *file_priv,
 static int i915_execbuffer(struct drm_device *dev, void *data,
                           struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
        drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
-               dev_priv->sarea_priv;
+               master_priv->sarea_priv;
        struct drm_i915_execbuffer *exec_buf = data;
        struct drm_i915_batchbuffer *batch = &exec_buf->batch;
        struct drm_fence_arg *fence_arg = &exec_buf->fence_arg;
@@ -1354,21 +1354,22 @@ out_err0:
 }
 #endif
 
-static int i915_do_cleanup_pageflip(struct drm_device * dev)
+int i915_do_cleanup_pageflip(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       int i, planes, num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
+       int i, planes, num_pages;
 
        DRM_DEBUG("\n");
-
-       for (i = 0, planes = 0; i < 2; i++)
-               if (dev_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) {
-                       dev_priv->sarea_priv->pf_current_page =
-                               (dev_priv->sarea_priv->pf_current_page &
+       num_pages = master_priv->sarea_priv->third_handle ? 3 : 2;
+       for (i = 0, planes = 0; i < 2; i++) {
+               if (master_priv->sarea_priv->pf_current_page & (0x3 << (2 * i))) {
+                       master_priv->sarea_priv->pf_current_page =
+                               (master_priv->sarea_priv->pf_current_page &
                                 ~(0x3 << (2 * i))) | ((num_pages - 1) << (2 * i));
 
                        planes |= 1 << i;
                }
+       }
 
        if (planes)
                i915_dispatch_flip(dev, planes, 0);
@@ -1378,7 +1379,7 @@ static int i915_do_cleanup_pageflip(struct drm_device * dev)
 
 static int i915_flip_bufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-       drm_i915_flip_t *param = data;
+       struct drm_i915_flip *param = data;
 
        DRM_DEBUG("\n");
 
@@ -1400,8 +1401,8 @@ static int i915_flip_bufs(struct drm_device *dev, void *data, struct drm_file *f
 static int i915_getparam(struct drm_device *dev, void *data,
                         struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_getparam_t *param = data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_getparam *param = data;
        int value;
 
        if (!dev_priv) {
@@ -1438,7 +1439,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
 static int i915_setparam(struct drm_device *dev, void *data,
                         struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        drm_i915_setparam_t *param = data;
 
        if (!dev_priv) {
@@ -1470,6 +1471,26 @@ drm_i915_mmio_entry_t mmio_table[] = {
                I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE,
                0x2350,
                8
+       },
+       [MMIO_REGS_DOVSTA] = {
+               I915_MMIO_MAY_READ,
+               0x30008,
+               1
+       },
+       [MMIO_REGS_GAMMA] = {
+               I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE,
+               0x30010,
+               6
+       },
+       [MMIO_REGS_FENCE] = {
+               I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE,
+               0x2000,
+               8
+       },
+       [MMIO_REGS_FENCE_NEW] = {
+               I915_MMIO_MAY_READ|I915_MMIO_MAY_WRITE,
+               0x3000,
+               16
        }
 };
 
@@ -1479,8 +1500,8 @@ static int i915_mmio(struct drm_device *dev, void *data,
                     struct drm_file *file_priv)
 {
        uint32_t buf[8];
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_mmio_entry_t *e;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       drm_i915_mmio_entry_t *e;        
        drm_i915_mmio_t *mmio = data;
        void __iomem *base;
        int i;
@@ -1525,7 +1546,7 @@ static int i915_mmio(struct drm_device *dev, void *data,
 static int i915_set_status_page(struct drm_device *dev, void *data,
                                struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        drm_i915_hws_addr_t *hws = data;
 
        if (!dev_priv) {
@@ -1553,99 +1574,13 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
        dev_priv->hw_status_page = dev_priv->hws_map.handle;
 
        memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
-       I915_WRITE(0x02080, dev_priv->status_gfx_addr);
+       I915_WRITE(I915REG_HWS_PGA, dev_priv->status_gfx_addr);
        DRM_DEBUG("load hws 0x2080 with gfx mem 0x%x\n",
                        dev_priv->status_gfx_addr);
        DRM_DEBUG("load hws at %p\n", dev_priv->hw_status_page);
        return 0;
 }
 
-int i915_driver_load(struct drm_device *dev, unsigned long flags)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long base, size;
-       int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1;
-
-       /* i915 has 4 more counters */
-       dev->counters += 4;
-       dev->types[6] = _DRM_STAT_IRQ;
-       dev->types[7] = _DRM_STAT_PRIMARY;
-       dev->types[8] = _DRM_STAT_SECONDARY;
-       dev->types[9] = _DRM_STAT_DMA;
-
-       dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER);
-       if (dev_priv == NULL)
-               return -ENOMEM;
-
-       memset(dev_priv, 0, sizeof(drm_i915_private_t));
-
-       dev->dev_private = (void *)dev_priv;
-
-       /* Add register map (needed for suspend/resume) */
-       base = drm_get_resource_start(dev, mmio_bar);
-       size = drm_get_resource_len(dev, mmio_bar);
-
-       ret = drm_addmap(dev, base, size, _DRM_REGISTERS,
-               _DRM_KERNEL | _DRM_DRIVER, &dev_priv->mmio_map);
-
-#ifdef __linux__
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
-       intel_init_chipset_flush_compat(dev);
-#endif
-#endif
-
-       return ret;
-}
-
-int i915_driver_unload(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->mmio_map)
-               drm_rmmap(dev, dev_priv->mmio_map);
-
-       drm_free(dev->dev_private, sizeof(drm_i915_private_t),
-                DRM_MEM_DRIVER);
-#ifdef __linux__
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
-       intel_fini_chipset_flush_compat(dev);
-#endif
-#endif
-       return 0;
-}
-
-void i915_driver_lastclose(struct drm_device * dev)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-
-       if (drm_getsarea(dev) && dev_priv->sarea_priv)
-               i915_do_cleanup_pageflip(dev);
-       if (dev_priv->agp_heap)
-               i915_mem_takedown(&(dev_priv->agp_heap));
-
-       if (dev_priv->sarea_kmap.virtual) {
-               drm_bo_kunmap(&dev_priv->sarea_kmap);
-               dev_priv->sarea_kmap.virtual = NULL;
-               dev->lock.hw_lock = NULL;
-               dev->sigdata.lock = NULL;
-       }
-
-       if (dev_priv->sarea_bo) {
-               mutex_lock(&dev->struct_mutex);
-               drm_bo_usage_deref_locked(&dev_priv->sarea_bo);
-               mutex_unlock(&dev->struct_mutex);
-               dev_priv->sarea_bo = NULL;
-       }
-
-       i915_dma_cleanup(dev);
-}
-
-void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
-{
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       i915_mem_release(dev, file_priv, dev_priv->agp_heap);
-}
-
 struct drm_ioctl_desc i915_ioctls[] = {
        DRM_IOCTL_DEF(DRM_I915_INIT, i915_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
        DRM_IOCTL_DEF(DRM_I915_FLUSH, i915_flush_ioctl, DRM_AUTH),
@@ -1688,10 +1623,3 @@ int i915_driver_device_is_agp(struct drm_device * dev)
        return 1;
 }
 
-int i915_driver_firstopen(struct drm_device *dev)
-{
-#ifdef I915_HAVE_BUFFER
-       drm_bo_driver_init(dev);
-#endif
-       return 0;
-}
index b93df67..824aee2 100644 (file)
@@ -39,7 +39,7 @@
                                 * of chars for next/prev indices */
 #define I915_LOG_MIN_TEX_REGION_SIZE 14
 
-typedef struct _drm_i915_init {
+typedef struct drm_i915_init {
        enum {
                I915_INIT_DMA = 0x01,
                I915_CLEANUP_DMA = 0x02,
@@ -223,7 +223,7 @@ typedef struct drm_i915_batchbuffer {
 /* As above, but pass a pointer to userspace buffer which can be
  * validated by the kernel prior to sending to hardware.
  */
-typedef struct _drm_i915_cmdbuffer {
+typedef struct drm_i915_cmdbuffer {
        char __user *buf;       /* pointer to userspace command buffer */
        int sz;                 /* nr bytes in buf */
        int DR1;                /* hw flags for GFX_OP_DRAWRECT_INFO */
@@ -326,6 +326,10 @@ typedef struct drm_i915_vblank_swap {
 #define MMIO_REGS_CL_INVOCATION_COUNT          6
 #define MMIO_REGS_PS_INVOCATION_COUNT          7
 #define MMIO_REGS_PS_DEPTH_COUNT               8
+#define MMIO_REGS_DOVSTA                       9
+#define MMIO_REGS_GAMMA                                10
+#define MMIO_REGS_FENCE                                11
+#define MMIO_REGS_FENCE_NEW                    12
 
 typedef struct drm_i915_mmio_entry {
        unsigned int flag;
index 4d3ac0a..f6c0005 100644 (file)
@@ -71,7 +71,7 @@
 #define I915_MAX_VALIDATE_BUFFERS 4096
 #endif
 
-typedef struct _drm_i915_ring_buffer {
+struct drm_i915_ring_buffer {
        int tail_mask;
        unsigned long Start;
        unsigned long End;
@@ -81,7 +81,7 @@ typedef struct _drm_i915_ring_buffer {
        int tail;
        int space;
        drm_local_map_t map;
-} drm_i915_ring_buffer_t;
+};
 
 struct mem_block {
        struct mem_block *next;
@@ -91,22 +91,31 @@ struct mem_block {
        struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */
 };
 
-typedef struct _drm_i915_vbl_swap {
+struct drm_i915_vbl_swap {
        struct list_head head;
        drm_drawable_t drw_id;
        unsigned int plane;
        unsigned int sequence;
        int flip;
-} drm_i915_vbl_swap_t;
+       struct drm_minor *minor;
+};
 
-typedef struct drm_i915_private {
+struct drm_i915_master_private {
        drm_local_map_t *sarea;
+       struct drm_i915_sarea *sarea_priv;
+};
+       
+struct drm_i915_private {
+       struct drm_buffer_object *ring_buffer;
+
        drm_local_map_t *mmio_map;
 
-       drm_i915_sarea_t *sarea_priv;
-       drm_i915_ring_buffer_t ring;
+       unsigned long mmiobase;
+       unsigned long mmiolen;
 
-       drm_dma_handle_t *status_page_dmah;
+       struct drm_i915_ring_buffer ring;
+
+       struct drm_dma_handle *status_page_dmah;
        void *hw_status_page;
        dma_addr_t dma_status_page;
        uint32_t counter;
@@ -131,6 +140,8 @@ typedef struct drm_i915_private {
        uint32_t irq_enable_reg;
        int irq_enabled;
 
+       struct workqueue_struct *wq;
+
 #ifdef I915_HAVE_FENCE
        uint32_t flush_sequence;
        uint32_t flush_flags;
@@ -141,12 +152,18 @@ typedef struct drm_i915_private {
        void *agp_iomap;
        unsigned int max_validate_buffers;
        struct mutex cmdbuf_mutex;
+       size_t stolen_base;
 #endif
 
        DRM_SPINTYPE swaps_lock;
-       drm_i915_vbl_swap_t vbl_swaps;
+       struct drm_i915_vbl_swap vbl_swaps;
        unsigned int swaps_pending;
 
+       /* LVDS info */
+       int backlight_duty_cycle;  /* restore backlight to this value */
+       bool panel_wants_dither;
+       struct drm_display_mode *panel_fixed_mode;
+
        /* DRI2 sarea */
        struct drm_buffer_object *sarea_bo;
        struct drm_bo_kmap_obj sarea_kmap;
@@ -237,7 +254,7 @@ typedef struct drm_i915_private {
        u8 saveDACMASK;
        u8 saveDACDATA[256*3]; /* 256 3-byte colors */
        u8 saveCR[36];
-} drm_i915_private_t;
+};
 
 enum intel_chip_family {
        CHIP_I8XX = 0x01,
@@ -249,10 +266,12 @@ enum intel_chip_family {
 extern struct drm_ioctl_desc i915_ioctls[];
 extern int i915_max_ioctl;
 
+extern int i915_master_create(struct drm_device *dev, struct drm_master *master);
+extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master);
                                /* i915_dma.c */
 extern void i915_kernel_lost_context(struct drm_device * dev);
 extern int i915_driver_load(struct drm_device *, unsigned long flags);
-extern int i915_driver_unload(struct drm_device *);
+extern int i915_driver_unload(struct drm_device *dev);
 extern void i915_driver_lastclose(struct drm_device * dev);
 extern void i915_driver_preclose(struct drm_device *dev,
                                 struct drm_file *file_priv);
@@ -263,6 +282,8 @@ extern void i915_emit_breadcrumb(struct drm_device *dev);
 extern void i915_dispatch_flip(struct drm_device * dev, int pipes, int sync);
 extern int i915_emit_mi_flush(struct drm_device *dev, uint32_t flush);
 extern int i915_driver_firstopen(struct drm_device *dev);
+extern int i915_do_cleanup_pageflip(struct drm_device *dev);
+extern int i915_dma_cleanup(struct drm_device *dev);
 
 /* i915_irq.c */
 extern int i915_irq_emit(struct drm_device *dev, void *data,
@@ -279,13 +300,14 @@ extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
 extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
 extern int i915_emit_irq(struct drm_device * dev);
+extern void i915_enable_interrupt (struct drm_device *dev);
 extern int i915_enable_vblank(struct drm_device *dev, int crtc);
 extern void i915_disable_vblank(struct drm_device *dev, int crtc);
 extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);
 extern int i915_vblank_swap(struct drm_device *dev, void *data,
                            struct drm_file *file_priv);
-extern void i915_user_irq_on(drm_i915_private_t *dev_priv);
-extern void i915_user_irq_off(drm_i915_private_t *dev_priv);
+extern void i915_user_irq_on(struct drm_i915_private *dev_priv);
+extern void i915_user_irq_off(struct drm_i915_private *dev_priv);
 
 /* i915_mem.c */
 extern int i915_mem_alloc(struct drm_device *dev, void *data,
@@ -328,6 +350,12 @@ extern void intel_fini_chipset_flush_compat(struct drm_device *dev);
 #endif
 #endif
 
+
+/* modesetting */
+extern void intel_modeset_init(struct drm_device *dev);
+extern void intel_modeset_cleanup(struct drm_device *dev);
+
+
 #define I915_READ(reg)          DRM_READ32(dev_priv->mmio_map, (reg))
 #define I915_WRITE(reg,val)     DRM_WRITE32(dev_priv->mmio_map, (reg), (val))
 #define I915_READ16(reg)       DRM_READ16(dev_priv->mmio_map, (reg))
@@ -365,8 +393,31 @@ extern void intel_fini_chipset_flush_compat(struct drm_device *dev);
        I915_WRITE(LP_RING + RING_TAIL, outring);                       \
 } while(0)
 
+#define MI_NOOP        (0x00 << 23)
+
 extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 
+/*
+ * The Bridge device's PCI config space has information about the
+ * fb aperture size and the amount of pre-reserved memory.
+ */
+#define INTEL_GMCH_CTRL                0x52
+#define INTEL_GMCH_ENABLED     0x4
+#define INTEL_GMCH_MEM_MASK    0x1
+#define INTEL_GMCH_MEM_64M     0x1
+#define INTEL_GMCH_MEM_128M    0
+
+#define INTEL_855_GMCH_GMS_MASK                (0x7 << 4)
+#define INTEL_855_GMCH_GMS_DISABLED    (0x0 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_1M   (0x1 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_4M   (0x2 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_8M   (0x3 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_16M  (0x4 << 4)
+#define INTEL_855_GMCH_GMS_STOLEN_32M  (0x5 << 4)
+
+#define INTEL_915G_GMCH_GMS_STOLEN_48M (0x6 << 4)
+#define INTEL_915G_GMCH_GMS_STOLEN_64M (0x7 << 4)
+
 /* Extended config space */
 #define LBB 0xf4
 
@@ -433,6 +484,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 #define BB1_UNPROTECTED       (0<<0)
 #define BB2_END_ADDR_MASK     (~0x7)
 
+#define I915REG_HWS_PGA                0x02080
+
 /* Framebuffer compression */
 #define FBC_CFB_BASE           0x03200 /* 4k page aligned */
 #define FBC_LL_BASE            0x03204 /* 4k page aligned */
@@ -516,6 +569,63 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 #define I915_VBLANK_INTERRUPT_ENABLE   (1UL<<17)
 #define I915_VBLANK_CLEAR              (1UL<<1)
 
+#define GPIOA                  0x5010
+#define GPIOB                  0x5014
+#define GPIOC                  0x5018
+#define GPIOD                  0x501c
+#define GPIOE                  0x5020
+#define GPIOF                  0x5024
+#define GPIOG                  0x5028
+#define GPIOH                  0x502c
+# define GPIO_CLOCK_DIR_MASK           (1 << 0)
+# define GPIO_CLOCK_DIR_IN             (0 << 1)
+# define GPIO_CLOCK_DIR_OUT            (1 << 1)
+# define GPIO_CLOCK_VAL_MASK           (1 << 2)
+# define GPIO_CLOCK_VAL_OUT            (1 << 3)
+# define GPIO_CLOCK_VAL_IN             (1 << 4)
+# define GPIO_CLOCK_PULLUP_DISABLE     (1 << 5)
+# define GPIO_DATA_DIR_MASK            (1 << 8)
+# define GPIO_DATA_DIR_IN              (0 << 9)
+# define GPIO_DATA_DIR_OUT             (1 << 9)
+# define GPIO_DATA_VAL_MASK            (1 << 10)
+# define GPIO_DATA_VAL_OUT             (1 << 11)
+# define GPIO_DATA_VAL_IN              (1 << 12)
+# define GPIO_DATA_PULLUP_DISABLE      (1 << 13)
+
+/* p317, 319
+ */
+#define VCLK2_VCO_M        0x6008 /* treat as 16 bit? (includes msbs) */
+#define VCLK2_VCO_N        0x600a
+#define VCLK2_VCO_DIV_SEL  0x6012
+
+#define VCLK_DIVISOR_VGA0   0x6000
+#define VCLK_DIVISOR_VGA1   0x6004
+#define VCLK_POST_DIV      0x6010
+/** Selects a post divisor of 4 instead of 2. */
+# define VGA1_PD_P2_DIV_4      (1 << 15)
+/** Overrides the p2 post divisor field */
+# define VGA1_PD_P1_DIV_2      (1 << 13)
+# define VGA1_PD_P1_SHIFT      8
+/** P1 value is 2 greater than this field */
+# define VGA1_PD_P1_MASK       (0x1f << 8)
+/** Selects a post divisor of 4 instead of 2. */
+# define VGA0_PD_P2_DIV_4      (1 << 7)
+/** Overrides the p2 post divisor field */
+# define VGA0_PD_P1_DIV_2      (1 << 5)
+# define VGA0_PD_P1_SHIFT      0
+/** P1 value is 2 greater than this field */
+# define VGA0_PD_P1_MASK       (0x1f << 0)
+
+#define POST_DIV_SELECT        0x70
+#define POST_DIV_1             0x00
+#define POST_DIV_2             0x10
+#define POST_DIV_4             0x20
+#define POST_DIV_8             0x30
+#define POST_DIV_16            0x40
+#define POST_DIV_32            0x50
+#define VCO_LOOP_DIV_BY_4M     0x00
+#define VCO_LOOP_DIV_BY_16M    0x04
+
 #define SRX_INDEX              0x3c4
 #define SRX_DATA               0x3c5
 #define SR01                   1
@@ -524,6 +634,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 #define PPCR                   0x61204
 #define PPCR_ON                        (1<<0)
 
+#define DVOA                   0x61120
+#define DVOA_ON                        (1<<31)
 #define DVOB                   0x61140
 #define DVOB_ON                        (1<<31)
 #define DVOC                   0x61160
@@ -685,8 +797,14 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 
 #define SRC_COPY_BLT_CMD                ((2<<29)|(0x43<<22)|4)
 #define XY_SRC_COPY_BLT_CMD            ((2<<29)|(0x53<<22)|6)
+#define XY_MONO_SRC_COPY_IMM_BLT       ((2<<29)|(0x71<<22)|5)
 #define XY_SRC_COPY_BLT_WRITE_ALPHA    (1<<21)
 #define XY_SRC_COPY_BLT_WRITE_RGB      (1<<20)
+#define   BLT_DEPTH_8                  (0<<24)
+#define   BLT_DEPTH_16_565             (1<<24)
+#define   BLT_DEPTH_16_1555            (2<<24)
+#define   BLT_DEPTH_32                 (3<<24)
+#define   BLT_ROP_GXCOPY               (0xcc<<16)
 
 #define MI_BATCH_BUFFER                ((0x30<<23)|1)
 #define MI_BATCH_BUFFER_START  (0x31<<23)
@@ -728,6 +846,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 #define BACKLIGHT_MODULATION_FREQ_SHIFT                (17)
 
 #define BLC_PWM_CTL2           0x61250
+
 /**
  * This is the most significant 15 bits of the number of backlight cycles in a
  * complete cycle of the modulated backlight control.
@@ -1086,6 +1205,579 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 # define LVDS_B0B3_POWER_DOWN          (0 << 2)
 # define LVDS_B0B3_POWER_UP            (3 << 2)
 
+#define TV_CTL                 0x68000
+/** Enables the TV encoder */
+# define TV_ENC_ENABLE                 (1 << 31)
+/** Sources the TV encoder input from pipe B instead of A. */
+# define TV_ENC_PIPEB_SELECT           (1 << 30)
+/** Outputs composite video (DAC A only) */
+# define TV_ENC_OUTPUT_COMPOSITE       (0 << 28)
+/** Outputs SVideo video (DAC B/C) */
+# define TV_ENC_OUTPUT_SVIDEO          (1 << 28)
+/** Outputs Component video (DAC A/B/C) */
+# define TV_ENC_OUTPUT_COMPONENT       (2 << 28)
+/** Outputs Composite and SVideo (DAC A/B/C) */
+# define TV_ENC_OUTPUT_SVIDEO_COMPOSITE        (3 << 28)
+# define TV_TRILEVEL_SYNC              (1 << 21)
+/** Enables slow sync generation (945GM only) */
+# define TV_SLOW_SYNC                  (1 << 20)
+/** Selects 4x oversampling for 480i and 576p */
+# define TV_OVERSAMPLE_4X              (0 << 18)
+/** Selects 2x oversampling for 720p and 1080i */
+# define TV_OVERSAMPLE_2X              (1 << 18)
+/** Selects no oversampling for 1080p */
+# define TV_OVERSAMPLE_NONE            (2 << 18)
+/** Selects 8x oversampling */
+# define TV_OVERSAMPLE_8X              (3 << 18)
+/** Selects progressive mode rather than interlaced */
+# define TV_PROGRESSIVE                        (1 << 17)
+/** Sets the colorburst to PAL mode.  Required for non-M PAL modes. */
+# define TV_PAL_BURST                  (1 << 16)
+/** Field for setting delay of Y compared to C */
+# define TV_YC_SKEW_MASK               (7 << 12)
+/** Enables a fix for 480p/576p standard definition modes on the 915GM only */
+# define TV_ENC_SDP_FIX                        (1 << 11)
+/**
+ * Enables a fix for the 915GM only.
+ *
+ * Not sure what it does.
+ */
+# define TV_ENC_C0_FIX                 (1 << 10)
+/** Bits that must be preserved by software */
+# define TV_CTL_SAVE                   ((3 << 8) | (3 << 6))
+# define TV_FUSE_STATE_MASK            (3 << 4)
+/** Read-only state that reports all features enabled */
+# define TV_FUSE_STATE_ENABLED         (0 << 4)
+/** Read-only state that reports that Macrovision is disabled in hardware*/
+# define TV_FUSE_STATE_NO_MACROVISION  (1 << 4)
+/** Read-only state that reports that TV-out is disabled in hardware. */
+# define TV_FUSE_STATE_DISABLED                (2 << 4)
+/** Normal operation */
+# define TV_TEST_MODE_NORMAL           (0 << 0)
+/** Encoder test pattern 1 - combo pattern */
+# define TV_TEST_MODE_PATTERN_1                (1 << 0)
+/** Encoder test pattern 2 - full screen vertical 75% color bars */
+# define TV_TEST_MODE_PATTERN_2                (2 << 0)
+/** Encoder test pattern 3 - full screen horizontal 75% color bars */
+# define TV_TEST_MODE_PATTERN_3                (3 << 0)
+/** Encoder test pattern 4 - random noise */
+# define TV_TEST_MODE_PATTERN_4                (4 << 0)
+/** Encoder test pattern 5 - linear color ramps */
+# define TV_TEST_MODE_PATTERN_5                (5 << 0)
+/**
+ * This test mode forces the DACs to 50% of full output.
+ *
+ * This is used for load detection in combination with TVDAC_SENSE_MASK
+ */
+# define TV_TEST_MODE_MONITOR_DETECT   (7 << 0)
+# define TV_TEST_MODE_MASK             (7 << 0)
+/** @} */
+
+/** @defgroup TV_DAC
+ * @{
+ */
+#define TV_DAC                 0x68004
+/**
+ * Reports that DAC state change logic has reported change (RO).
+ *
+ * This gets cleared when TV_DAC_STATE_EN is cleared
+*/
+# define TVDAC_STATE_CHG               (1 << 31)
+# define TVDAC_SENSE_MASK              (7 << 28)
+/** Reports that DAC A voltage is above the detect threshold */
+# define TVDAC_A_SENSE                 (1 << 30)
+/** Reports that DAC B voltage is above the detect threshold */
+# define TVDAC_B_SENSE                 (1 << 29)
+/** Reports that DAC C voltage is above the detect threshold */
+# define TVDAC_C_SENSE                 (1 << 28)
+/**
+ * Enables DAC state detection logic, for load-based TV detection.
+ *
+ * The PLL of the chosen pipe (in TV_CTL) must be running, and the encoder set
+ * to off, for load detection to work.
+ */
+# define TVDAC_STATE_CHG_EN            (1 << 27)
+/** Sets the DAC A sense value to high */
+# define TVDAC_A_SENSE_CTL             (1 << 26)
+/** Sets the DAC B sense value to high */
+# define TVDAC_B_SENSE_CTL             (1 << 25)
+/** Sets the DAC C sense value to high */
+# define TVDAC_C_SENSE_CTL             (1 << 24)
+/** Overrides the ENC_ENABLE and DAC voltage levels */
+# define DAC_CTL_OVERRIDE              (1 << 7)
+/** Sets the slew rate.  Must be preserved in software */
+# define ENC_TVDAC_SLEW_FAST           (1 << 6)
+# define DAC_A_1_3_V                   (0 << 4)
+# define DAC_A_1_1_V                   (1 << 4)
+# define DAC_A_0_7_V                   (2 << 4)
+# define DAC_A_OFF                     (3 << 4)
+# define DAC_B_1_3_V                   (0 << 2)
+# define DAC_B_1_1_V                   (1 << 2)
+# define DAC_B_0_7_V                   (2 << 2)
+# define DAC_B_OFF                     (3 << 2)
+# define DAC_C_1_3_V                   (0 << 0)
+# define DAC_C_1_1_V                   (1 << 0)
+# define DAC_C_0_7_V                   (2 << 0)
+# define DAC_C_OFF                     (3 << 0)
+/** @} */
+
+/**
+ * CSC coefficients are stored in a floating point format with 9 bits of
+ * mantissa and 2 or 3 bits of exponent.  The exponent is represented as 2**-n,
+ * where 2-bit exponents are unsigned n, and 3-bit exponents are signed n with
+ * -1 (0x3) being the only legal negative value.
+ */
+#define TV_CSC_Y               0x68010
+# define TV_RY_MASK                    0x07ff0000
+# define TV_RY_SHIFT                   16
+# define TV_GY_MASK                    0x00000fff
+# define TV_GY_SHIFT                   0
+
+#define TV_CSC_Y2              0x68014
+# define TV_BY_MASK                    0x07ff0000
+# define TV_BY_SHIFT                   16
+/**
+ * Y attenuation for component video.
+ *
+ * Stored in 1.9 fixed point.
+ */
+# define TV_AY_MASK                    0x000003ff
+# define TV_AY_SHIFT                   0
+
+#define TV_CSC_U               0x68018
+# define TV_RU_MASK                    0x07ff0000
+# define TV_RU_SHIFT                   16
+# define TV_GU_MASK                    0x000007ff
+# define TV_GU_SHIFT                   0
+
+#define TV_CSC_U2              0x6801c
+# define TV_BU_MASK                    0x07ff0000
+# define TV_BU_SHIFT                   16
+/**
+ * U attenuation for component video.
+ *
+ * Stored in 1.9 fixed point.
+ */
+# define TV_AU_MASK                    0x000003ff
+# define TV_AU_SHIFT                   0
+
+#define TV_CSC_V               0x68020
+# define TV_RV_MASK                    0x0fff0000
+# define TV_RV_SHIFT                   16
+# define TV_GV_MASK                    0x000007ff
+# define TV_GV_SHIFT                   0
+
+#define TV_CSC_V2              0x68024
+# define TV_BV_MASK                    0x07ff0000
+# define TV_BV_SHIFT                   16
+/**
+ * V attenuation for component video.
+ *
+ * Stored in 1.9 fixed point.
+ */
+# define TV_AV_MASK                    0x000007ff
+# define TV_AV_SHIFT                   0
+
+/** @defgroup TV_CSC_KNOBS
+ * @{
+ */
+#define TV_CLR_KNOBS           0x68028
+/** 2s-complement brightness adjustment */
+# define TV_BRIGHTNESS_MASK            0xff000000
+# define TV_BRIGHTNESS_SHIFT           24
+/** Contrast adjustment, as a 2.6 unsigned floating point number */
+# define TV_CONTRAST_MASK              0x00ff0000
+# define TV_CONTRAST_SHIFT             16
+/** Saturation adjustment, as a 2.6 unsigned floating point number */
+# define TV_SATURATION_MASK            0x0000ff00
+# define TV_SATURATION_SHIFT           8
+/** Hue adjustment, as an integer phase angle in degrees */
+# define TV_HUE_MASK                   0x000000ff
+# define TV_HUE_SHIFT                  0
+/** @} */
+
+/** @defgroup TV_CLR_LEVEL
+ * @{
+ */
+#define TV_CLR_LEVEL           0x6802c
+/** Controls the DAC level for black */
+# define TV_BLACK_LEVEL_MASK           0x01ff0000
+# define TV_BLACK_LEVEL_SHIFT          16
+/** Controls the DAC level for blanking */
+# define TV_BLANK_LEVEL_MASK           0x000001ff
+# define TV_BLANK_LEVEL_SHIFT          0
+/* @} */
+
+/** @defgroup TV_H_CTL_1
+ * @{
+ */
+#define TV_H_CTL_1             0x68030
+/** Number of pixels in the hsync. */
+# define TV_HSYNC_END_MASK             0x1fff0000
+# define TV_HSYNC_END_SHIFT            16
+/** Total number of pixels minus one in the line (display and blanking). */
+# define TV_HTOTAL_MASK                        0x00001fff
+# define TV_HTOTAL_SHIFT               0
+/** @} */
+
+/** @defgroup TV_H_CTL_2
+ * @{
+ */
+#define TV_H_CTL_2             0x68034
+/** Enables the colorburst (needed for non-component color) */
+# define TV_BURST_ENA                  (1 << 31)
+/** Offset of the colorburst from the start of hsync, in pixels minus one. */
+# define TV_HBURST_START_SHIFT         16
+# define TV_HBURST_START_MASK          0x1fff0000
+/** Length of the colorburst */
+# define TV_HBURST_LEN_SHIFT           0
+# define TV_HBURST_LEN_MASK            0x0001fff
+/** @} */
+
+/** @defgroup TV_H_CTL_3
+ * @{
+ */
+#define TV_H_CTL_3             0x68038
+/** End of hblank, measured in pixels minus one from start of hsync */
+# define TV_HBLANK_END_SHIFT           16
+# define TV_HBLANK_END_MASK            0x1fff0000
+/** Start of hblank, measured in pixels minus one from start of hsync */
+# define TV_HBLANK_START_SHIFT         0
+# define TV_HBLANK_START_MASK          0x0001fff
+/** @} */
+
+/** @defgroup TV_V_CTL_1
+ * @{
+ */
+#define TV_V_CTL_1             0x6803c
+/** XXX */
+# define TV_NBR_END_SHIFT              16
+# define TV_NBR_END_MASK               0x07ff0000
+/** XXX */
+# define TV_VI_END_F1_SHIFT            8
+# define TV_VI_END_F1_MASK             0x00003f00
+/** XXX */
+# define TV_VI_END_F2_SHIFT            0
+# define TV_VI_END_F2_MASK             0x0000003f
+/** @} */
+
+/** @defgroup TV_V_CTL_2
+ * @{
+ */
+#define TV_V_CTL_2             0x68040
+/** Length of vsync, in half lines */
+# define TV_VSYNC_LEN_MASK             0x07ff0000
+# define TV_VSYNC_LEN_SHIFT            16
+/** Offset of the start of vsync in field 1, measured in one less than the
+ * number of half lines.
+ */
+# define TV_VSYNC_START_F1_MASK                0x00007f00
+# define TV_VSYNC_START_F1_SHIFT       8
+/**
+ * Offset of the start of vsync in field 2, measured in one less than the
+ * number of half lines.
+ */
+# define TV_VSYNC_START_F2_MASK                0x0000007f
+# define TV_VSYNC_START_F2_SHIFT       0
+/** @} */
+
+/** @defgroup TV_V_CTL_3
+ * @{
+ */
+#define TV_V_CTL_3             0x68044
+/** Enables generation of the equalization signal */
+# define TV_EQUAL_ENA                  (1 << 31)
+/** Length of vsync, in half lines */
+# define TV_VEQ_LEN_MASK               0x007f0000
+# define TV_VEQ_LEN_SHIFT              16
+/** Offset of the start of equalization in field 1, measured in one less than
+ * the number of half lines.
+ */
+# define TV_VEQ_START_F1_MASK          0x0007f00
+# define TV_VEQ_START_F1_SHIFT         8
+/**
+ * Offset of the start of equalization in field 2, measured in one less than
+ * the number of half lines.
+ */
+# define TV_VEQ_START_F2_MASK          0x000007f
+# define TV_VEQ_START_F2_SHIFT         0
+/** @} */
+
+/** @defgroup TV_V_CTL_4
+ * @{
+ */
+#define TV_V_CTL_4             0x68048
+/**
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F1_MASK       0x003f0000
+# define TV_VBURST_START_F1_SHIFT      16
+/**
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F1_MASK         0x000000ff
+# define TV_VBURST_END_F1_SHIFT                0
+/** @} */
+
+/** @defgroup TV_V_CTL_5
+ * @{
+ */
+#define TV_V_CTL_5             0x6804c
+/**
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F2_MASK       0x003f0000
+# define TV_VBURST_START_F2_SHIFT      16
+/**
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F2_MASK         0x000000ff
+# define TV_VBURST_END_F2_SHIFT                0
+/** @} */
+
+/** @defgroup TV_V_CTL_6
+ * @{
+ */
+#define TV_V_CTL_6             0x68050
+/**
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F3_MASK       0x003f0000
+# define TV_VBURST_START_F3_SHIFT      16
+/**
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F3_MASK         0x000000ff
+# define TV_VBURST_END_F3_SHIFT                0
+/** @} */
+
+/** @defgroup TV_V_CTL_7
+ * @{
+ */
+#define TV_V_CTL_7             0x68054
+/**
+ * Offset to start of vertical colorburst, measured in one less than the
+ * number of lines from vertical start.
+ */
+# define TV_VBURST_START_F4_MASK       0x003f0000
+# define TV_VBURST_START_F4_SHIFT      16
+/**
+ * Offset to the end of vertical colorburst, measured in one less than the
+ * number of lines from the start of NBR.
+ */
+# define TV_VBURST_END_F4_MASK         0x000000ff
+# define TV_VBURST_END_F4_SHIFT                0
+/** @} */
+
+/** @defgroup TV_SC_CTL_1
+ * @{
+ */
+#define TV_SC_CTL_1            0x68060
+/** Turns on the first subcarrier phase generation DDA */
+# define TV_SC_DDA1_EN                 (1 << 31)
+/** Turns on the first subcarrier phase generation DDA */
+# define TV_SC_DDA2_EN                 (1 << 30)
+/** Turns on the first subcarrier phase generation DDA */
+# define TV_SC_DDA3_EN                 (1 << 29)
+/** Sets the subcarrier DDA to reset frequency every other field */
+# define TV_SC_RESET_EVERY_2           (0 << 24)
+/** Sets the subcarrier DDA to reset frequency every fourth field */
+# define TV_SC_RESET_EVERY_4           (1 << 24)
+/** Sets the subcarrier DDA to reset frequency every eighth field */
+# define TV_SC_RESET_EVERY_8           (2 << 24)
+/** Sets the subcarrier DDA to never reset the frequency */
+# define TV_SC_RESET_NEVER             (3 << 24)
+/** Sets the peak amplitude of the colorburst.*/
+# define TV_BURST_LEVEL_MASK           0x00ff0000
+# define TV_BURST_LEVEL_SHIFT          16
+/** Sets the increment of the first subcarrier phase generation DDA */
+# define TV_SCDDA1_INC_MASK            0x00000fff
+# define TV_SCDDA1_INC_SHIFT           0
+/** @} */
+
+/** @defgroup TV_SC_CTL_2
+ * @{
+ */
+#define TV_SC_CTL_2            0x68064
+/** Sets the rollover for the second subcarrier phase generation DDA */
+# define TV_SCDDA2_SIZE_MASK           0x7fff0000
+# define TV_SCDDA2_SIZE_SHIFT          16
+/** Sets the increent of the second subcarrier phase generation DDA */
+# define TV_SCDDA2_INC_MASK            0x00007fff
+# define TV_SCDDA2_INC_SHIFT           0
+/** @} */
+
+/** @defgroup TV_SC_CTL_3
+ * @{
+ */
+#define TV_SC_CTL_3            0x68068
+/** Sets the rollover for the third subcarrier phase generation DDA */
+# define TV_SCDDA3_SIZE_MASK           0x7fff0000
+# define TV_SCDDA3_SIZE_SHIFT          16
+/** Sets the increent of the third subcarrier phase generation DDA */
+# define TV_SCDDA3_INC_MASK            0x00007fff
+# define TV_SCDDA3_INC_SHIFT           0
+/** @} */
+
+/** @defgroup TV_WIN_POS
+ * @{
+ */
+#define TV_WIN_POS             0x68070
+/** X coordinate of the display from the start of horizontal active */
+# define TV_XPOS_MASK                  0x1fff0000
+# define TV_XPOS_SHIFT                 16
+/** Y coordinate of the display from the start of vertical active (NBR) */
+# define TV_YPOS_MASK                  0x00000fff
+# define TV_YPOS_SHIFT                 0
+/** @} */
+
+/** @defgroup TV_WIN_SIZE
+ * @{
+ */
+#define TV_WIN_SIZE            0x68074
+/** Horizontal size of the display window, measured in pixels*/
+# define TV_XSIZE_MASK                 0x1fff0000
+# define TV_XSIZE_SHIFT                        16
+/**
+ * Vertical size of the display window, measured in pixels.
+ *
+ * Must be even for interlaced modes.
+ */
+# define TV_YSIZE_MASK                 0x00000fff
+# define TV_YSIZE_SHIFT                        0
+/** @} */
+
+/** @defgroup TV_FILTER_CTL_1
+ * @{
+ */
+#define TV_FILTER_CTL_1                0x68080
+/**
+ * Enables automatic scaling calculation.
+ *
+ * If set, the rest of the registers are ignored, and the calculated values can
+ * be read back from the register.
+ */
+# define TV_AUTO_SCALE                 (1 << 31)
+/**
+ * Disables the vertical filter.
+ *
+ * This is required on modes more than 1024 pixels wide */
+# define TV_V_FILTER_BYPASS            (1 << 29)
+/** Enables adaptive vertical filtering */
+# define TV_VADAPT                     (1 << 28)
+# define TV_VADAPT_MODE_MASK           (3 << 26)
+/** Selects the least adaptive vertical filtering mode */
+# define TV_VADAPT_MODE_LEAST          (0 << 26)
+/** Selects the moderately adaptive vertical filtering mode */
+# define TV_VADAPT_MODE_MODERATE       (1 << 26)
+/** Selects the most adaptive vertical filtering mode */
+# define TV_VADAPT_MODE_MOST           (3 << 26)
+/**
+ * Sets the horizontal scaling factor.
+ *
+ * This should be the fractional part of the horizontal scaling factor divided
+ * by the oversampling rate.  TV_HSCALE should be less than 1, and set to:
+ *
+ * (src width - 1) / ((oversample * dest width) - 1)
+ */
+# define TV_HSCALE_FRAC_MASK           0x00003fff
+# define TV_HSCALE_FRAC_SHIFT          0
+/** @} */
+
+/** @defgroup TV_FILTER_CTL_2
+ * @{
+ */
+#define TV_FILTER_CTL_2                0x68084
+/**
+ * Sets the integer part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * TV_VSCALE should be (src height - 1) / ((interlace * dest height) - 1)
+ */
+# define TV_VSCALE_INT_MASK            0x00038000
+# define TV_VSCALE_INT_SHIFT           15
+/**
+ * Sets the fractional part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * \sa TV_VSCALE_INT_MASK
+ */
+# define TV_VSCALE_FRAC_MASK           0x00007fff
+# define TV_VSCALE_FRAC_SHIFT          0
+/** @} */
+
+/** @defgroup TV_FILTER_CTL_3
+ * @{
+ */
+#define TV_FILTER_CTL_3                0x68088
+/**
+ * Sets the integer part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * TV_VSCALE should be (src height - 1) / (1/4 * (dest height - 1))
+ *
+ * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes.
+ */
+# define TV_VSCALE_IP_INT_MASK         0x00038000
+# define TV_VSCALE_IP_INT_SHIFT                15
+/**
+ * Sets the fractional part of the 3.15 fixed-point vertical scaling factor.
+ *
+ * For progressive modes, TV_VSCALE_IP_INT should be set to zeroes.
+ *
+ * \sa TV_VSCALE_IP_INT_MASK
+ */
+# define TV_VSCALE_IP_FRAC_MASK                0x00007fff
+# define TV_VSCALE_IP_FRAC_SHIFT               0
+/** @} */
+
+/** @defgroup TV_CC_CONTROL
+ * @{
+ */
+#define TV_CC_CONTROL          0x68090
+# define TV_CC_ENABLE                  (1 << 31)
+/**
+ * Specifies which field to send the CC data in.
+ *
+ * CC data is usually sent in field 0.
+ */
+# define TV_CC_FID_MASK                        (1 << 27)
+# define TV_CC_FID_SHIFT               27
+/** Sets the horizontal position of the CC data.  Usually 135. */
+# define TV_CC_HOFF_MASK               0x03ff0000
+# define TV_CC_HOFF_SHIFT              16
+/** Sets the vertical position of the CC data.  Usually 21 */
+# define TV_CC_LINE_MASK               0x0000003f
+# define TV_CC_LINE_SHIFT              0
+/** @} */
+
+/** @defgroup TV_CC_DATA
+ * @{
+ */
+#define TV_CC_DATA             0x68094
+# define TV_CC_RDY                     (1 << 31)
+/** Second word of CC data to be transmitted. */
+# define TV_CC_DATA_2_MASK             0x007f0000
+# define TV_CC_DATA_2_SHIFT            16
+/** First word of CC data to be transmitted. */
+# define TV_CC_DATA_1_MASK             0x0000007f
+# define TV_CC_DATA_1_SHIFT            0
+/** @}
+ */
+
+/** @{ */
+#define TV_H_LUMA_0            0x68100
+#define TV_H_LUMA_59           0x681ec
+#define TV_H_CHROMA_0          0x68200
+#define TV_H_CHROMA_59         0x682ec
+#define TV_V_LUMA_0            0x68300
+#define TV_V_LUMA_42           0x683a8
+#define TV_V_CHROMA_0          0x68400
+#define TV_V_CHROMA_42         0x684a8
+
 #define PIPEACONF 0x70008
 #define PIPEACONF_ENABLE       (1<<31)
 #define PIPEACONF_DISABLE      0
@@ -1177,13 +1869,17 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
  */
 
 #define SWF0                   0x71410
+#define SWF1                   0x71414
+#define SWF2                   0x71418
+#define SWF3                   0x7141c
+#define SWF4                   0x71420
+#define SWF5                   0x71424
+#define SWF6                   0x71428
 
-/*
- * 855 scratch registers.
- */
 #define SWF10                  0x70410
-
 #define SWF30                  0x72414
+#define SWF31                  0x72418
+#define SWF32                  0x7241c
 
 /*
  * Overlay registers.  These are overlay registers accessed via MMIO.
@@ -1200,6 +1896,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
 #define OGAMC2                 0x3001c
 #define OGAMC1                 0x30020
 #define OGAMC0                 0x30024
+
 /*
  * Palette registers
  */
diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c
new file mode 100644 (file)
index 0000000..1f22d17
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2007 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * Copyright Â© 2002, 2003 David Dawes <dawes@xfree86.org>
+ *                   2004 Sylvain Meyer
+ *
+ * GPL/BSD dual license
+ */
+#include "drmP.h"
+#include "drm.h"
+#include "drm_sarea.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+/**
+ * i915_probe_agp - get AGP bootup configuration
+ * @pdev: PCI device
+ * @aperture_size: returns AGP aperture configured size
+ * @preallocated_size: returns size of BIOS preallocated AGP space
+ *
+ * Since Intel integrated graphics are UMA, the BIOS has to set aside
+ * some RAM for the framebuffer at early boot.  This code figures out
+ * how much was set aside so we can use it for our own purposes.
+ */
+int i915_probe_agp(struct pci_dev *pdev, unsigned long *aperture_size,
+                  unsigned long *preallocated_size)
+{
+       struct pci_dev *bridge_dev;
+       u16 tmp = 0;
+       unsigned long overhead;
+
+       bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0));
+       if (!bridge_dev) {
+               DRM_ERROR("bridge device not found\n");
+               return -1;
+       }
+
+       /* Get the fb aperture size and "stolen" memory amount. */
+       pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &tmp);
+       pci_dev_put(bridge_dev);
+
+       *aperture_size = 1024 * 1024;
+       *preallocated_size = 1024 * 1024;
+
+       switch (pdev->device) {
+       case PCI_DEVICE_ID_INTEL_82830_CGC:
+       case PCI_DEVICE_ID_INTEL_82845G_IG:
+       case PCI_DEVICE_ID_INTEL_82855GM_IG:
+       case PCI_DEVICE_ID_INTEL_82865_IG:
+               if ((tmp & INTEL_GMCH_MEM_MASK) == INTEL_GMCH_MEM_64M)
+                       *aperture_size *= 64;
+               else
+                       *aperture_size *= 128;
+               break;
+       default:
+               /* 9xx supports large sizes, just look at the length */
+               *aperture_size = pci_resource_len(pdev, 2);
+               break;
+       }
+
+       /*
+        * Some of the preallocated space is taken by the GTT
+        * and popup.  GTT is 1K per MB of aperture size, and popup is 4K.
+        */
+       overhead = (*aperture_size / 1024) + 4096;
+       switch (tmp & INTEL_855_GMCH_GMS_MASK) {
+       case INTEL_855_GMCH_GMS_STOLEN_1M:
+               break; /* 1M already */
+       case INTEL_855_GMCH_GMS_STOLEN_4M:
+               *preallocated_size *= 4;
+               break;
+       case INTEL_855_GMCH_GMS_STOLEN_8M:
+               *preallocated_size *= 8;
+               break;
+       case INTEL_855_GMCH_GMS_STOLEN_16M:
+               *preallocated_size *= 16;
+               break;
+       case INTEL_855_GMCH_GMS_STOLEN_32M:
+               *preallocated_size *= 32;
+               break;
+       case INTEL_915G_GMCH_GMS_STOLEN_48M:
+               *preallocated_size *= 48;
+               break;
+       case INTEL_915G_GMCH_GMS_STOLEN_64M:
+               *preallocated_size *= 64;
+               break;
+       case INTEL_855_GMCH_GMS_DISABLED:
+               DRM_ERROR("video memory is disabled\n");
+               return -1;
+       default:
+               DRM_ERROR("unexpected GMCH_GMS value: 0x%02x\n",
+                       tmp & INTEL_855_GMCH_GMS_MASK);
+               return -1;
+       }
+       *preallocated_size -= overhead;
+
+       return 0;
+}
+
+/**
+ * i915_driver_load - setup chip and create an initial config
+ * @dev: DRM device
+ * @flags: startup flags
+ *
+ * The driver load routine has to do several things:
+ *   - drive output discovery via intel_modeset_init()
+ *   - initialize the memory manager
+ *   - allocate initial config memory
+ *   - setup the DRM framebuffer with the allocated memory
+ */
+int i915_driver_load(struct drm_device *dev, unsigned long flags)
+{
+       struct drm_i915_private *dev_priv;
+       unsigned long agp_size, prealloc_size;
+       int size, ret;
+
+       dev_priv = drm_alloc(sizeof(struct drm_i915_private), DRM_MEM_DRIVER);
+       if (dev_priv == NULL)
+               return -ENOMEM;
+
+       memset(dev_priv, 0, sizeof(struct drm_i915_private));
+       dev->dev_private = (void *)dev_priv;
+//     dev_priv->flags = flags;
+
+       /* i915 has 4 more counters */
+       dev->counters += 4;
+       dev->types[6] = _DRM_STAT_IRQ;
+       dev->types[7] = _DRM_STAT_PRIMARY;
+       dev->types[8] = _DRM_STAT_SECONDARY;
+       dev->types[9] = _DRM_STAT_DMA;
+
+       if (IS_I9XX(dev)) {
+               pci_read_config_dword(dev->pdev, 0x5C, &dev_priv->stolen_base);
+               DRM_DEBUG("stolen base %p\n", (void*)dev_priv->stolen_base);
+       }
+
+       if (IS_I9XX(dev)) {
+               dev_priv->mmiobase = drm_get_resource_start(dev, 0);
+               dev_priv->mmiolen = drm_get_resource_len(dev, 0);
+               dev->mode_config.fb_base =
+                       drm_get_resource_start(dev, 2) & 0xff000000;
+       } else if (drm_get_resource_start(dev, 1)) {
+               dev_priv->mmiobase = drm_get_resource_start(dev, 1);
+               dev_priv->mmiolen = drm_get_resource_len(dev, 1);
+               dev->mode_config.fb_base =
+                       drm_get_resource_start(dev, 0) & 0xff000000;
+       } else {
+               DRM_ERROR("Unable to find MMIO registers\n");
+               return -ENODEV;
+       }
+
+       DRM_DEBUG("fb_base: 0x%08lx\n", dev->mode_config.fb_base);
+
+       ret = drm_addmap(dev, dev_priv->mmiobase, dev_priv->mmiolen,
+                        _DRM_REGISTERS, _DRM_KERNEL|_DRM_READ_ONLY|_DRM_DRIVER, &dev_priv->mmio_map);
+       if (ret != 0) {
+               DRM_ERROR("Cannot add mapping for MMIO registers\n");
+               return ret;
+       }
+
+#ifdef __linux__
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+        intel_init_chipset_flush_compat(dev);
+#endif
+#endif
+
+       /*
+        * Initialize the memory manager for local and AGP space
+        */
+       drm_bo_driver_init(dev);
+
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               i915_probe_agp(dev->pdev, &agp_size, &prealloc_size);
+               printk("setting up %ld bytes of VRAM space\n", prealloc_size);
+               printk("setting up %ld bytes of TT space\n", (agp_size - prealloc_size));
+               drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, prealloc_size >> PAGE_SHIFT, 1);
+               drm_bo_init_mm(dev, DRM_BO_MEM_TT, prealloc_size >> PAGE_SHIFT, (agp_size - prealloc_size) >> PAGE_SHIFT, 1);
+               
+               I915_WRITE(LP_RING + RING_LEN, 0);
+               I915_WRITE(LP_RING + RING_HEAD, 0);
+               I915_WRITE(LP_RING + RING_TAIL, 0);
+
+               size = PRIMARY_RINGBUFFER_SIZE;
+               ret = drm_buffer_object_create(dev, size, drm_bo_type_kernel,
+                                              DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE |
+                                              DRM_BO_FLAG_MEM_VRAM |
+                                              DRM_BO_FLAG_NO_EVICT,
+                                              DRM_BO_HINT_DONT_FENCE, 0x1, 0,
+                                              &dev_priv->ring_buffer);
+               if (ret < 0) {
+                       DRM_ERROR("Unable to allocate or pin ring buffer\n");
+                       return -EINVAL;
+               }
+               
+               /* remap the buffer object properly */
+               dev_priv->ring.Start = dev_priv->ring_buffer->offset;
+               dev_priv->ring.End = dev_priv->ring.Start + size;
+               dev_priv->ring.Size = size;
+               dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
+
+               /* FIXME: need wrapper with PCI mem checks */
+               ret = drm_mem_reg_ioremap(dev, &dev_priv->ring_buffer->mem,
+                                         (void **) &dev_priv->ring.virtual_start);
+               if (ret)
+                       DRM_ERROR("error mapping ring buffer: %d\n", ret);
+               
+               DRM_DEBUG("ring start %08lX, %p, %08lX\n", dev_priv->ring.Start,
+                         dev_priv->ring.virtual_start, dev_priv->ring.Size);
+
+       //
+
+               memset((void *)(dev_priv->ring.virtual_start), 0, dev_priv->ring.Size);
+               
+               I915_WRITE(LP_RING + RING_START, dev_priv->ring.Start);
+               I915_WRITE(LP_RING + RING_LEN,
+                          ((dev_priv->ring.Size - 4096) & RING_NR_PAGES) |
+                          (RING_NO_REPORT | RING_VALID));
+
+               /* We are using separate values as placeholders for mechanisms for
+                * private backbuffer/depthbuffer usage.
+                */
+               dev_priv->use_mi_batchbuffer_start = 0;
+               
+               /* Allow hardware batchbuffers unless told otherwise.
+                */
+               dev_priv->allow_batchbuffer = 1;
+
+               /* Program Hardware Status Page */
+               if (!IS_G33(dev)) {
+                       dev_priv->status_page_dmah = 
+                               drm_pci_alloc(dev, PAGE_SIZE, PAGE_SIZE, 0xffffffff);
+                       
+                       if (!dev_priv->status_page_dmah) {
+                               dev->dev_private = (void *)dev_priv;
+                               i915_dma_cleanup(dev);
+                               DRM_ERROR("Can not allocate hardware status page\n");
+                               return -ENOMEM;
+                       }
+                       dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;
+                       dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
+                       
+                       memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+                       
+                       I915_WRITE(I915REG_HWS_PGA, dev_priv->dma_status_page);
+               }
+               DRM_DEBUG("Enabled hardware status page\n");
+
+               dev_priv->wq = create_singlethread_workqueue("i915");
+               if (dev_priv == 0) {
+                 DRM_DEBUG("Error\n");
+               }
+
+               intel_modeset_init(dev);
+               drm_initial_config(dev, false);
+
+               drm_mm_print(&dev->bm.man[DRM_BO_MEM_VRAM].manager, "VRAM");
+               drm_mm_print(&dev->bm.man[DRM_BO_MEM_TT].manager, "TT");
+
+               drm_irq_install(dev);
+       }
+
+       return 0;
+}
+
+int i915_driver_unload(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE(LP_RING + RING_LEN, 0);
+
+
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               intel_modeset_cleanup(dev);
+       }
+
+#if 0
+       if (dev_priv->ring.virtual_start) {
+               drm_core_ioremapfree(&dev_priv->ring.map, dev);
+       }
+#endif
+       if (dev_priv->sarea_kmap.virtual) {
+               drm_bo_kunmap(&dev_priv->sarea_kmap);
+               dev_priv->sarea_kmap.virtual = NULL;
+               dev->primary->master->lock.hw_lock = NULL;
+               dev->sigdata.lock = NULL;
+       }
+
+       if (dev_priv->sarea_bo) {
+               mutex_lock(&dev->struct_mutex);
+               drm_bo_usage_deref_locked(&dev_priv->sarea_bo);
+               mutex_unlock(&dev->struct_mutex);
+               dev_priv->sarea_bo = NULL;
+       }
+
+       if (dev_priv->status_page_dmah) {
+               drm_pci_free(dev, dev_priv->status_page_dmah);
+               dev_priv->status_page_dmah = NULL;
+               dev_priv->hw_status_page = NULL;
+               dev_priv->dma_status_page = 0;
+               /* Need to rewrite hardware status page */
+               I915_WRITE(I915REG_HWS_PGA, 0x1ffff000);
+       }
+
+       if (dev_priv->status_gfx_addr) {
+               dev_priv->status_gfx_addr = 0;
+               drm_core_ioremapfree(&dev_priv->hws_map, dev);
+               I915_WRITE(I915REG_HWS_PGA, 0x1ffff000);
+       }
+
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               drm_mem_reg_iounmap(dev, &dev_priv->ring_buffer->mem,
+                                   dev_priv->ring.virtual_start);
+
+               DRM_DEBUG("usage is %d\n", atomic_read(&dev_priv->ring_buffer->usage));
+               mutex_lock(&dev->struct_mutex);
+               drm_bo_usage_deref_locked(&dev_priv->ring_buffer);
+
+               if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT, 1)) {
+                       DRM_ERROR("Memory manager type 3 not clean. "
+                                 "Delaying takedown\n");
+               }
+               if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM, 1)) {
+                       DRM_ERROR("Memory manager type 3 not clean. "
+                                 "Delaying takedown\n");
+               }
+               mutex_unlock(&dev->struct_mutex);
+       }
+
+       drm_bo_driver_finish(dev);
+
+#ifdef __linux__
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+        intel_init_chipset_flush_compat(dev);
+#endif
+#endif
+
+        DRM_DEBUG("%p\n", dev_priv->mmio_map);
+        drm_rmmap(dev, dev_priv->mmio_map);
+
+       drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
+
+       dev->dev_private = NULL;
+       return 0;
+}
+
+int i915_master_create(struct drm_device *dev, struct drm_master *master)
+{
+       struct drm_i915_master_private *master_priv;
+       unsigned long sareapage;
+       int ret;
+
+       master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER);
+       if (!master_priv)
+               return -ENOMEM;
+
+       /* prebuild the SAREA */
+       sareapage = max(SAREA_MAX, PAGE_SIZE);
+       ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER,
+                        &master_priv->sarea);
+       if (ret) {
+               DRM_ERROR("SAREA setup failed\n");
+               return ret;
+       }
+       master_priv->sarea_priv = master_priv->sarea->handle + sizeof(struct drm_sarea);
+       master_priv->sarea_priv->pf_current_page = 0;
+
+       master->driver_priv = master_priv;
+       return 0;
+}
+
+void i915_master_destroy(struct drm_device *dev, struct drm_master *master)
+{
+       struct drm_i915_master_private *master_priv = master->driver_priv;
+
+       if (!master_priv)
+               return;
+
+        drm_rmmap(dev, master_priv->sarea);
+       drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER);
+
+       master->driver_priv = NULL;
+}
+
+void i915_driver_preclose(struct drm_device * dev, struct drm_file *file_priv)
+{
+        struct drm_i915_private *dev_priv = dev->dev_private;
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               i915_mem_release(dev, file_priv, dev_priv->agp_heap);
+}
+
+void i915_driver_lastclose(struct drm_device * dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               return;
+
+       if (dev_priv->agp_heap)
+               i915_mem_takedown(&(dev_priv->agp_heap));
+       
+       i915_dma_cleanup(dev);
+}
+
+int i915_driver_firstopen(struct drm_device *dev)
+{
+       if (drm_core_check_feature(dev, DRIVER_MODESET))
+               return 0;
+
+       drm_bo_driver_init(dev);
+       return 0;
+}
index 126f037..b9d137f 100644 (file)
 #include "i915_drm.h"
 #include "i915_drv.h"
 
+#include "intel_drv.h"
+
 #define USER_INT_FLAG (1<<1)
 #define VSYNC_PIPEB_FLAG (1<<5)
 #define VSYNC_PIPEA_FLAG (1<<7)
+#define HOTPLUG_FLAG (1 << 17)
 
 #define MAX_NOPID ((u32)~0)
 
@@ -49,7 +52,7 @@
 static int
 i915_get_pipe(struct drm_device *dev, int plane)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
        u32 dspcntr;
 
        dspcntr = plane ? I915_READ(DSPBCNTR) : I915_READ(DSPACNTR);
@@ -86,7 +89,7 @@ i915_get_plane(struct drm_device *dev, int pipe)
 static int
 i915_pipe_enabled(struct drm_device *dev, int pipe)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
        unsigned long pipeconf = pipe ? PIPEBCONF : PIPEACONF;
 
        if (I915_READ(pipeconf) & PIPEACONF_ENABLE)
@@ -104,8 +107,8 @@ static void
 i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw,
                         int plane)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
+       struct drm_i915_sarea *sarea_priv = master_priv->sarea_priv;
        u16 x1, y1, x2, y2;
        int pf_planes = 1 << plane;
 
@@ -149,19 +152,19 @@ i915_dispatch_vsync_flip(struct drm_device *dev, struct drm_drawable_info *drw,
  */
 static void i915_vblank_tasklet(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
        struct list_head *list, *tmp, hits, *hit;
        int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages;
        unsigned counter[2];
        struct drm_drawable_info *drw;
-       drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
+       struct drm_i915_sarea *sarea_priv;
        u32 cpp = dev_priv->cpp,  offsets[3];
        u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
                                XY_SRC_COPY_BLT_WRITE_ALPHA |
                                XY_SRC_COPY_BLT_WRITE_RGB)
                             : XY_SRC_COPY_BLT_CMD;
-       u32 pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) |
-                         (cpp << 23) | (1 << 24);
+       u32 pitchropcpp;
        RING_LOCALS;
 
        counter[0] = drm_vblank_count(dev, 0);
@@ -182,13 +185,19 @@ static void i915_vblank_tasklet(struct drm_device *dev)
 
        /* Find buffer swaps scheduled for this vertical blank */
        list_for_each_safe(list, tmp, &dev_priv->vbl_swaps.head) {
-               drm_i915_vbl_swap_t *vbl_swap =
-                       list_entry(list, drm_i915_vbl_swap_t, head);
+               struct drm_i915_vbl_swap *vbl_swap =
+                       list_entry(list, struct drm_i915_vbl_swap, head);
                int pipe = i915_get_pipe(dev, vbl_swap->plane);
 
                if ((counter[pipe] - vbl_swap->sequence) > (1<<23))
                        continue;
 
+               master_priv = vbl_swap->minor->master->driver_priv;
+               sarea_priv = master_priv->sarea_priv;
+               
+               pitchropcpp = (sarea_priv->pitch * cpp) | (0xcc << 16) |
+                       (cpp << 23) | (1 << 24);
+
                list_del(list);
                dev_priv->swaps_pending--;
                drm_vblank_put(dev, pipe);
@@ -206,8 +215,8 @@ static void i915_vblank_tasklet(struct drm_device *dev)
                }
 
                list_for_each(hit, &hits) {
-                       drm_i915_vbl_swap_t *swap_cmp =
-                               list_entry(hit, drm_i915_vbl_swap_t, head);
+                       struct drm_i915_vbl_swap *swap_cmp =
+                               list_entry(hit, struct drm_i915_vbl_swap, head);
                        struct drm_drawable_info *drw_cmp =
                                drm_get_drawable_info(dev, swap_cmp->drw_id);
 
@@ -264,8 +273,8 @@ static void i915_vblank_tasklet(struct drm_device *dev)
                        lower[0] = lower[1] = sarea_priv->height;
 
                list_for_each(hit, &hits) {
-                       drm_i915_vbl_swap_t *swap_hit =
-                               list_entry(hit, drm_i915_vbl_swap_t, head);
+                       struct drm_i915_vbl_swap *swap_hit =
+                               list_entry(hit, struct drm_i915_vbl_swap, head);
                        struct drm_clip_rect *rect;
                        int num_rects, plane, front, back;
                        unsigned short top, bottom;
@@ -303,7 +312,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
                        top = upper[plane];
                        bottom = lower[plane];
 
-                       front = (dev_priv->sarea_priv->pf_current_page >>
+                       front = (master_priv->sarea_priv->pf_current_page >>
                                 (2 * plane)) & 0x3;
                        back = (front + 1) % num_pages;
 
@@ -333,8 +342,8 @@ static void i915_vblank_tasklet(struct drm_device *dev)
        DRM_SPINUNLOCK(&dev->drw_lock);
 
        list_for_each_safe(hit, tmp, &hits) {
-               drm_i915_vbl_swap_t *swap_hit =
-                       list_entry(hit, drm_i915_vbl_swap_t, head);
+               struct drm_i915_vbl_swap *swap_hit =
+                       list_entry(hit, struct drm_i915_vbl_swap, head);
 
                list_del(hit);
 
@@ -344,7 +353,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
 #if 0
 static int i915_in_vblank(struct drm_device *dev, int pipe)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
        unsigned long pipedsl, vblank, vtotal;
        unsigned long vbl_start, vbl_end, cur_line;
 
@@ -365,7 +374,7 @@ static int i915_in_vblank(struct drm_device *dev, int pipe)
 #endif
 u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
        unsigned long high_frame;
        unsigned long low_frame;
        u32 high1, high2, low, count;
@@ -416,24 +425,196 @@ u32 i915_get_vblank_counter(struct drm_device *dev, int plane)
        return count;
 }
 
+#define HOTPLUG_CMD_CRT 1
+#define HOTPLUG_CMD_CRT_DIS 2
+#define HOTPLUG_CMD_SDVOB 4
+#define HOTPLUG_CMD_SDVOC 8
+
+static struct drm_device *hotplug_dev;
+static int hotplug_cmd = 0;
+static spinlock_t hotplug_lock = SPIN_LOCK_UNLOCKED;
+
+static void i915_hotplug_crt(struct drm_device *dev, bool connected)
+{
+       struct drm_output *output;
+       struct intel_output *iout;
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       /* find the crt output */
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+               iout = output->driver_private;
+               if (iout->type == INTEL_OUTPUT_ANALOG)
+                       break;
+               else
+                       iout = 0;
+       }
+
+       if (iout == 0)
+               goto unlock;
+
+       drm_hotplug_stage_two(dev, output, connected);
+
+unlock:
+       mutex_unlock(&dev->mode_config.mutex);
+}
+
+static void i915_hotplug_sdvo(struct drm_device *dev, int sdvoB)
+{
+       struct drm_output *output = 0;
+       enum drm_output_status status;
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       output = intel_sdvo_find(dev, sdvoB);
+
+       if (!output) {
+               DRM_ERROR("could not find sdvo%s output\n", sdvoB ? "B" : "C");
+               goto unlock;
+       }
+
+       status = output->funcs->detect(output);
+
+       if (status != output_status_connected)
+               drm_hotplug_stage_two(dev, output, false);
+       else
+               drm_hotplug_stage_two(dev, output, true);
+
+       /* wierd hw bug, sdvo stop sending interupts */
+       intel_sdvo_set_hotplug(output, 1);
+
+unlock:
+       mutex_unlock(&dev->mode_config.mutex);
+}
+/*
+ * This code is called in a more safe envirmoent to handle the hotplugs.
+ * Add code here for hotplug love to userspace.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+static void i915_hotplug_work_func(void *work)
+#else
+static void i915_hotplug_work_func(struct work_struct *work)
+#endif
+{
+       struct drm_device *dev = hotplug_dev;
+       int crt;
+       int crtDis;
+       int sdvoB;
+       int sdvoC;
+
+       spin_lock(&hotplug_lock);
+       crt = hotplug_cmd & HOTPLUG_CMD_CRT;
+       crtDis = hotplug_cmd & HOTPLUG_CMD_CRT_DIS;
+       sdvoB = hotplug_cmd & HOTPLUG_CMD_SDVOB;
+       sdvoC = hotplug_cmd & HOTPLUG_CMD_SDVOC;
+       hotplug_cmd = 0;
+       spin_unlock(&hotplug_lock);
+
+       if (crt)
+               i915_hotplug_crt(dev, true);
+       if (crtDis)
+               i915_hotplug_crt(dev, false);
+
+       if (sdvoB)
+               i915_hotplug_sdvo(dev, 1);
+
+       if (sdvoC)
+               i915_hotplug_sdvo(dev, 0);
+
+}
+
+static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+       static DECLARE_WORK(hotplug, i915_hotplug_work_func, NULL);
+#else
+       static DECLARE_WORK(hotplug, i915_hotplug_work_func);
+#endif
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       hotplug_dev = dev;
+
+       if (stat & CRT_HOTPLUG_INT_STATUS) {
+               DRM_DEBUG("CRT event\n");
+
+               if (stat & CRT_HOTPLUG_MONITOR_MASK) {
+                       spin_lock(&hotplug_lock);
+                       hotplug_cmd |= HOTPLUG_CMD_CRT;
+                       spin_unlock(&hotplug_lock);
+               } else {
+                       spin_lock(&hotplug_lock);
+                       hotplug_cmd |= HOTPLUG_CMD_CRT_DIS;
+                       spin_unlock(&hotplug_lock);
+               }
+       }
+
+       if (stat & SDVOB_HOTPLUG_INT_STATUS) {
+               DRM_DEBUG("sDVOB event\n");
+
+               spin_lock(&hotplug_lock);
+               hotplug_cmd |= HOTPLUG_CMD_SDVOB;
+               spin_unlock(&hotplug_lock);
+       }
+
+       if (stat & SDVOC_HOTPLUG_INT_STATUS) {
+               DRM_DEBUG("sDVOC event\n");
+
+               spin_lock(&hotplug_lock);
+               hotplug_cmd |= HOTPLUG_CMD_SDVOC;
+               spin_unlock(&hotplug_lock);
+       }
+
+       queue_work(dev_priv->wq, &hotplug);
+
+       return 0;
+}
+
 irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
 {
        struct drm_device *dev = (struct drm_device *) arg;
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u16 temp;
+       struct drm_i915_master_private *master_priv;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+       u32 temp = 0;
+       u32 temp2;
        u32 pipea_stats, pipeb_stats;
 
        pipea_stats = I915_READ(I915REG_PIPEASTAT);
        pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
 
-       temp = I915_READ16(I915REG_INT_IDENTITY_R);
+       /* On i8xx hw the IIR and IER are 16bit on i9xx its 32bit */
+       if (IS_I9XX(dev))
+               temp = I915_READ(I915REG_INT_IDENTITY_R);
+       else
+               temp = I915_READ16(I915REG_INT_IDENTITY_R);
+
+       temp2 = temp;
+       temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG);
 
 #if 0
+       /* ugly despamification of pipeb event irq */
+       if (temp & (0xFFFFFFF ^ ((1 << 5) | (1 << 7)))) {
+               DRM_DEBUG("IIR %08x\n", temp2);
+               DRM_DEBUG("MSK %08x\n", dev_priv->irq_enable_reg | USER_INT_FLAG);
+               DRM_DEBUG("M&I %08x\n", temp);
+               DRM_DEBUG("HOT %08x\n", I915_READ(PORT_HOTPLUG_STAT));
+       }
+#else
+#if 0
        DRM_DEBUG("flag=%08x\n", temp);
 #endif
+#endif
+
        if (temp == 0)
                return IRQ_NONE;
 
+       if (IS_I9XX(dev)) {
+               I915_WRITE(I915REG_INT_IDENTITY_R, temp);
+               (void) I915_READ(I915REG_INT_IDENTITY_R);
+       } else {
+               I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
+               (void) I915_READ16(I915REG_INT_IDENTITY_R);
+       }
+
        /*
         * Clear the PIPE(A|B)STAT regs before the IIR otherwise
         * we may get extra interrupts.
@@ -444,6 +625,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                           pipea_stats | I915_VBLANK_INTERRUPT_ENABLE |
                           I915_VBLANK_CLEAR);
        }
+
        if (temp & VSYNC_PIPEB_FLAG) {
                drm_handle_vblank(dev, i915_get_plane(dev, 1));
                I915_WRITE(I915REG_PIPEBSTAT,
@@ -454,12 +636,15 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
        I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
        (void) I915_READ16(I915REG_INT_IDENTITY_R); /* Flush posted write */
 
+       DRM_READMEMORYBARRIER();
+
        temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG | VSYNC_PIPEA_FLAG |
                 VSYNC_PIPEB_FLAG);
 
-       if (dev_priv->sarea_priv)
-               dev_priv->sarea_priv->last_dispatch =
-                       READ_BREADCRUMB(dev_priv);
+       if (dev->primary->master) {
+               master_priv = dev->primary->master->driver_priv;
+               master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+       }
 
        if (temp & USER_INT_FLAG) {
                DRM_WAKEUP(&dev_priv->irq_queue);
@@ -473,12 +658,23 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
                        drm_locked_tasklet(dev, i915_vblank_tasklet);
        }
 
+       /* for now lest just ack it */
+       if (temp & (1 << 17)) {
+               DRM_DEBUG("Hotplug event received\n");
+
+               temp2 = I915_READ(PORT_HOTPLUG_STAT);
+
+               i915_run_hotplug_tasklet(dev, temp2);
+
+               I915_WRITE(PORT_HOTPLUG_STAT,temp2);
+       }
+
        return IRQ_HANDLED;
 }
 
 int i915_emit_irq(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        RING_LOCALS;
 
        i915_kernel_lost_context(dev);
@@ -495,7 +691,7 @@ int i915_emit_irq(struct drm_device *dev)
        return dev_priv->counter;
 }
 
-void i915_user_irq_on(drm_i915_private_t *dev_priv)
+void i915_user_irq_on(struct drm_i915_private *dev_priv)
 {
        DRM_SPINLOCK(&dev_priv->user_irq_lock);
        if (dev_priv->irq_enabled && (++dev_priv->user_irq_refcount == 1)){
@@ -505,8 +701,8 @@ void i915_user_irq_on(drm_i915_private_t *dev_priv)
        DRM_SPINUNLOCK(&dev_priv->user_irq_lock);
 
 }
-
-void i915_user_irq_off(drm_i915_private_t *dev_priv)
+               
+void i915_user_irq_off(struct drm_i915_private *dev_priv)
 {
        DRM_SPINLOCK(&dev_priv->user_irq_lock);
        if (dev_priv->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
@@ -519,7 +715,8 @@ void i915_user_irq_off(drm_i915_private_t *dev_priv)
 
 static int i915_wait_irq(struct drm_device * dev, int irq_nr)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+       struct drm_i915_master_private *master_priv;
        int ret = 0;
 
        DRM_DEBUG("irq_nr=%d breadcrumb=%d\n", irq_nr,
@@ -537,10 +734,12 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
                DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
                          READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
        }
+       
+       if (dev->primary->master) {
+               master_priv = dev->primary->master->driver_priv;
+               master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+       }
 
-       if (dev_priv->sarea_priv)
-               dev_priv->sarea_priv->last_dispatch =
-                       READ_BREADCRUMB(dev_priv);
        return ret;
 }
 
@@ -549,8 +748,8 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
 int i915_irq_emit(struct drm_device *dev, void *data,
                         struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_irq_emit_t *emit = data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_irq_emit *emit = data;
        int result;
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
@@ -575,8 +774,8 @@ int i915_irq_emit(struct drm_device *dev, void *data,
 int i915_irq_wait(struct drm_device *dev, void *data,
                  struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_irq_wait_t *irqwait = data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_irq_wait *irqwait = data;
 
        if (!dev_priv) {
                DRM_ERROR("called with no initialization\n");
@@ -588,9 +787,9 @@ int i915_irq_wait(struct drm_device *dev, void *data,
 
 int i915_enable_vblank(struct drm_device *dev, int plane)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
        int pipe = i915_get_pipe(dev, plane);
-
+       
        switch (pipe) {
        case 0:
                dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG;
@@ -611,7 +810,7 @@ int i915_enable_vblank(struct drm_device *dev, int plane)
 
 void i915_disable_vblank(struct drm_device *dev, int plane)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
        int pipe = i915_get_pipe(dev, plane);
 
        switch (pipe) {
@@ -630,13 +829,48 @@ void i915_disable_vblank(struct drm_device *dev, int plane)
        I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
 }
 
-static void i915_enable_interrupt (struct drm_device *dev)
+void i915_enable_interrupt (struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+       struct drm_output *o;
+
        dev_priv->irq_enable_reg |= USER_INT_FLAG;
 
-       I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+       if (IS_I9XX(dev) && dev->mode_config.num_output) {
+               dev_priv->irq_enable_reg |= HOTPLUG_FLAG;
+
+               /* Activate the CRT */
+               I915_WRITE(PORT_HOTPLUG_EN, CRT_HOTPLUG_INT_EN);
+
+               /* SDVOB */
+               o = intel_sdvo_find(dev, 1);
+               if (o && intel_sdvo_supports_hotplug(o)) {
+                       intel_sdvo_set_hotplug(o, 1);
+                       I915_WRITE(PORT_HOTPLUG_EN, SDVOB_HOTPLUG_INT_EN);
+               }
+
+               /* SDVOC */
+               o = intel_sdvo_find(dev, 0);
+               if (o && intel_sdvo_supports_hotplug(o)) {
+                       intel_sdvo_set_hotplug(o, 1);
+                       I915_WRITE(PORT_HOTPLUG_EN, SDVOC_HOTPLUG_INT_EN);
+               }
+
+       }
+
+       if (IS_I9XX(dev)) {
+               I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+       } else {
+               I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg);
+       }
+
+       DRM_DEBUG("HEN %08x\n",I915_READ(PORT_HOTPLUG_EN));
+       DRM_DEBUG("HST %08x\n",I915_READ(PORT_HOTPLUG_STAT));
+       DRM_DEBUG("IER %08x\n",I915_READ(I915REG_INT_ENABLE_R));
+       DRM_DEBUG("SDB %08x\n",I915_READ(SDVOB));
+
+       I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
+
        dev_priv->irq_enabled = 1;
 }
 
@@ -645,8 +879,8 @@ static void i915_enable_interrupt (struct drm_device *dev)
 int i915_vblank_pipe_set(struct drm_device *dev, void *data,
                         struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_vblank_pipe_t *pipe = data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_vblank_pipe *pipe = data;
 
        if (!dev_priv) {
                DRM_ERROR("called with no initialization\n");
@@ -666,8 +900,8 @@ int i915_vblank_pipe_set(struct drm_device *dev, void *data,
 int i915_vblank_pipe_get(struct drm_device *dev, void *data,
                         struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_vblank_pipe_t *pipe = data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_vblank_pipe *pipe = data;
        u16 flag;
 
        if (!dev_priv) {
@@ -691,9 +925,10 @@ int i915_vblank_pipe_get(struct drm_device *dev, void *data,
 int i915_vblank_swap(struct drm_device *dev, void *data,
                     struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_vblank_swap_t *swap = data;
-       drm_i915_vbl_swap_t *vbl_swap;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_master_private *master_priv;
+       struct drm_i915_vblank_swap *swap = data;
+       struct drm_i915_vbl_swap *vbl_swap;
        unsigned int pipe, seqtype, curseq, plane;
        unsigned long irqflags;
        struct list_head *list;
@@ -704,7 +939,12 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
-       if (!dev_priv->sarea_priv || dev_priv->sarea_priv->rotation) {
+       if (!dev->primary->master)
+               return -EINVAL;
+
+       master_priv = dev->primary->master->driver_priv;
+
+       if (master_priv->sarea_priv->rotation) {
                DRM_DEBUG("Rotation not supported\n");
                return -EINVAL;
        }
@@ -787,7 +1027,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
        DRM_SPINLOCK_IRQSAVE(&dev_priv->swaps_lock, irqflags);
 
        list_for_each(list, &dev_priv->vbl_swaps.head) {
-               vbl_swap = list_entry(list, drm_i915_vbl_swap_t, head);
+               vbl_swap = list_entry(list, struct drm_i915_vbl_swap, head);
 
                if (vbl_swap->drw_id == swap->drawable &&
                    vbl_swap->plane == plane &&
@@ -825,6 +1065,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
        vbl_swap->plane = plane;
        vbl_swap->sequence = swap->sequence;
        vbl_swap->flip = (swap->seqtype & _DRM_VBLANK_FLIP);
+       vbl_swap->minor = file_priv->minor;
 
        if (vbl_swap->flip)
                swap->sequence++;
@@ -843,16 +1084,22 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
 */
 void i915_driver_irq_preinstall(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
 
        I915_WRITE16(I915REG_HWSTAM, 0xeffe);
-       I915_WRITE16(I915REG_INT_MASK_R, 0x0);
-       I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
+       if (IS_I9XX(dev)) {
+               I915_WRITE(I915REG_INT_MASK_R, 0x0);
+               I915_WRITE(I915REG_INT_ENABLE_R, 0x0);
+       } else {
+               I915_WRITE16(I915REG_INT_MASK_R, 0x0);
+               I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
+       }
+
 }
 
 int i915_driver_irq_postinstall(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
        int ret, num_pipes = 2;
 
        DRM_SPININIT(&dev_priv->swaps_lock, "swap");
@@ -882,17 +1129,28 @@ int i915_driver_irq_postinstall(struct drm_device * dev)
 
 void i915_driver_irq_uninstall(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u16 temp;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+       u32 temp;
 
        if (!dev_priv)
                return;
 
        dev_priv->irq_enabled = 0;
-       I915_WRITE16(I915REG_HWSTAM, 0xffff);
-       I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
-       I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
 
-       temp = I915_READ16(I915REG_INT_IDENTITY_R);
-       I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
+
+       if(IS_I9XX(dev)) {
+               I915_WRITE(I915REG_HWSTAM, 0xffffffff);
+               I915_WRITE(I915REG_INT_MASK_R, 0xffffffff);
+               I915_WRITE(I915REG_INT_ENABLE_R, 0x0);
+
+               temp = I915_READ(I915REG_INT_IDENTITY_R);
+               I915_WRITE(I915REG_INT_IDENTITY_R, temp);
+       } else {
+               I915_WRITE16(I915REG_HWSTAM, 0xffff);
+               I915_WRITE16(I915REG_INT_MASK_R, 0xffff);
+               I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
+
+               temp = I915_READ16(I915REG_INT_IDENTITY_R);
+               I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
+       }
 }
index 6126a60..15d63de 100644 (file)
@@ -45,8 +45,9 @@
  */
 static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
+       struct drm_i915_sarea *sarea_priv = master_priv->sarea_priv;
        struct drm_tex_region *list;
        unsigned shift, nr;
        unsigned start;
@@ -256,7 +257,7 @@ void i915_mem_takedown(struct mem_block **heap)
        *heap = NULL;
 }
 
-static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region)
+static struct mem_block **get_heap(struct drm_i915_private * dev_priv, int region)
 {
        switch (region) {
        case I915_MEM_REGION_AGP:
@@ -271,8 +272,8 @@ static struct mem_block **get_heap(drm_i915_private_t * dev_priv, int region)
 int i915_mem_alloc(struct drm_device *dev, void *data,
                   struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_mem_alloc_t *alloc = data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_mem_alloc *alloc = data;
        struct mem_block *block, **heap;
 
        if (!dev_priv) {
@@ -309,8 +310,8 @@ int i915_mem_alloc(struct drm_device *dev, void *data,
 int i915_mem_free(struct drm_device *dev, void *data,
                  struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_mem_free_t *memfree = data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_mem_free *memfree = data;
        struct mem_block *block, **heap;
 
        if (!dev_priv) {
@@ -337,8 +338,8 @@ int i915_mem_free(struct drm_device *dev, void *data,
 int i915_mem_init_heap(struct drm_device *dev, void *data,
                       struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_mem_init_heap_t *initheap = data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_mem_init_heap *initheap = data;
        struct mem_block **heap;
 
        if (!dev_priv) {
@@ -361,8 +362,8 @@ int i915_mem_init_heap(struct drm_device *dev, void *data,
 int i915_mem_destroy_heap( struct drm_device *dev, void *data,
                           struct drm_file *file_priv )
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       drm_i915_mem_destroy_heap_t *destroyheap = data;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_mem_destroy_heap *destroyheap = data;
        struct mem_block **heap;
 
        if ( !dev_priv ) {
index 0971f97..67536c2 100644 (file)
@@ -434,8 +434,17 @@ typedef struct {
        int pfCurrentPage;      /* which buffer is being displayed? */
        int crtc2_base;         /* CRTC2 frame offset */
        int tiling_enabled;     /* set by drm, read by 2d + 3d clients */
+
+       unsigned int last_fence;
 } drm_radeon_sarea_t;
 
+/* The only fence class we support */
+#define DRM_RADEON_FENCE_CLASS_ACCEL 0
+/* Fence type that guarantees read-write flush */
+#define DRM_RADEON_FENCE_TYPE_RW 2
+/* cache flushes programmed just before the fence */
+#define DRM_RADEON_FENCE_FLAG_FLUSHED 0x01000000
+
 /* WARNING: If you change any of these defines, make sure to change the
  * defines in the Xserver file (xf86drmRadeon.h)
  *
diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h
new file mode 100644 (file)
index 0000000..903de97
--- /dev/null
@@ -0,0 +1,607 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * Copyright 2007 Dave Airlie
+ * Copyright 2007 Alex Deucher
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ */
+/*
+ * Authors:
+ *    Jérôme Glisse <glisse@freedesktop.org>
+ */
+#ifndef __RADEON_MS_H__
+#define __RADEON_MS_H__
+
+#include "radeon_ms_drv.h"
+#include "radeon_ms_reg.h"
+#include "radeon_ms_drm.h"
+#include "radeon_ms_rom.h"
+#include "radeon_ms_properties.h"
+
+#define DRIVER_AUTHOR      "Jerome Glisse, Dave Airlie,  Gareth Hughes, "\
+                          "Keith Whitwell, others."
+#define DRIVER_NAME        "radeon_ms"
+#define DRIVER_DESC        "radeon kernel modesetting"
+#define DRIVER_DATE        "20071108"
+#define DRIVER_MAJOR        1
+#define DRIVER_MINOR        0
+#define DRIVER_PATCHLEVEL   0
+
+enum radeon_bus_type {
+       RADEON_PCI = 0x10000,
+       RADEON_AGP = 0x20000,
+       RADEON_PCIE = 0x30000,
+};
+
+enum radeon_family {
+       CHIP_R100,
+       CHIP_RV100,
+       CHIP_RS100,
+       CHIP_RV200,
+       CHIP_RS200,
+       CHIP_R200,
+       CHIP_RV250,
+       CHIP_RS300,
+       CHIP_RV280,
+       CHIP_R300,
+       CHIP_R350,
+       CHIP_R360,
+       CHIP_RV350,
+       CHIP_RV370,
+       CHIP_RV380,
+       CHIP_RS400,
+       CHIP_RV410,
+       CHIP_R420,
+       CHIP_R430,
+       CHIP_R480,
+       CHIP_LAST,
+};
+
+enum radeon_monitor_type {
+       MT_UNKNOWN = -1,
+       MT_NONE    = 0,
+       MT_CRT     = 1,
+       MT_LCD     = 2,
+       MT_DFP     = 3,
+       MT_CTV     = 4,
+       MT_STV     = 5
+};
+
+enum radeon_connector_type {
+       CONNECTOR_NONE,
+       CONNECTOR_PROPRIETARY,
+       CONNECTOR_VGA,
+       CONNECTOR_DVI_I,
+       CONNECTOR_DVI_D,
+       CONNECTOR_CTV,
+       CONNECTOR_STV,
+       CONNECTOR_UNSUPPORTED
+};
+
+enum radeon_output_type {
+       OUTPUT_NONE,
+       OUTPUT_DAC1,
+       OUTPUT_DAC2,
+       OUTPUT_TMDS,
+       OUTPUT_LVDS
+};
+
+struct radeon_state;
+
+struct radeon_ms_crtc {
+       int             crtc;
+       uint16_t        lut_r[256];
+       uint16_t        lut_g[256];
+       uint16_t        lut_b[256];
+};
+
+struct radeon_ms_i2c {
+       struct drm_device           *drm_dev;
+       uint32_t                    reg;
+       struct i2c_adapter          adapter;
+       struct i2c_algo_bit_data    algo;
+};
+
+struct radeon_ms_connector {
+       struct radeon_ms_i2c    *i2c;
+       struct edid             *edid;
+       struct drm_output       *output;
+       int                     type;
+       int                     monitor_type;
+       int                     crtc;
+       uint32_t                i2c_reg;
+       char                    outputs[RADEON_MAX_OUTPUTS];
+       char                    name[32];
+};
+
+struct radeon_ms_output {
+       int                         type;
+       struct drm_device           *dev;
+       struct radeon_ms_connector  *connector;
+       int (*initialize)(struct radeon_ms_output *output);
+       enum drm_output_status (*detect)(struct radeon_ms_output *output);
+       void (*dpms)(struct radeon_ms_output *output, int mode);
+       int (*get_modes)(struct radeon_ms_output *output);
+       bool (*mode_fixup)(struct radeon_ms_output *output,
+                       struct drm_display_mode *mode,
+                       struct drm_display_mode *adjusted_mode);
+       int (*mode_set)(struct radeon_ms_output *output,
+                       struct drm_display_mode *mode,
+                       struct drm_display_mode *adjusted_mode);
+       void (*restore)(struct radeon_ms_output *output,
+                       struct radeon_state *state);
+       void (*save)(struct radeon_ms_output *output,
+                       struct radeon_state *state);
+};
+
+struct radeon_state {
+       /* memory */
+       uint32_t        config_aper_0_base;
+       uint32_t        config_aper_1_base;
+       uint32_t        config_aper_size;
+       uint32_t        mc_fb_location;
+       uint32_t        display_base_addr;
+       /* irq */
+       uint32_t        gen_int_cntl;
+       /* pci */
+       uint32_t        aic_ctrl;
+       uint32_t        aic_pt_base;
+       uint32_t        aic_pt_base_lo;
+       uint32_t        aic_pt_base_hi;
+       uint32_t        aic_lo_addr;
+       uint32_t        aic_hi_addr;
+       /* agp */
+       uint32_t        agp_cntl;
+       uint32_t        agp_command;
+       uint32_t        agp_base;
+       uint32_t        agp_base_2;
+       uint32_t        bus_cntl;
+       uint32_t        mc_agp_location;
+       /* cp */
+       uint32_t        cp_rb_cntl;
+       uint32_t        cp_rb_base;
+       uint32_t        cp_rb_rptr_addr;
+       uint32_t        cp_rb_wptr;
+       uint32_t        cp_rb_wptr_delay;
+       uint32_t        scratch_umsk;
+       uint32_t        scratch_addr;
+       /* pcie */
+       uint32_t        pcie_tx_gart_cntl;
+       uint32_t        pcie_tx_gart_discard_rd_addr_lo;
+       uint32_t        pcie_tx_gart_discard_rd_addr_hi;
+       uint32_t        pcie_tx_gart_base;
+       uint32_t        pcie_tx_gart_start_lo;
+       uint32_t        pcie_tx_gart_start_hi;
+       uint32_t        pcie_tx_gart_end_lo;
+       uint32_t        pcie_tx_gart_end_hi;
+       /* surface */
+       uint32_t        surface_cntl;
+       uint32_t        surface0_info;
+       uint32_t        surface0_lower_bound;
+       uint32_t        surface0_upper_bound;
+       uint32_t        surface1_info;
+       uint32_t        surface1_lower_bound;
+       uint32_t        surface1_upper_bound;
+       uint32_t        surface2_info;
+       uint32_t        surface2_lower_bound;
+       uint32_t        surface2_upper_bound;
+       uint32_t        surface3_info;
+       uint32_t        surface3_lower_bound;
+       uint32_t        surface3_upper_bound;
+       uint32_t        surface4_info;
+       uint32_t        surface4_lower_bound;
+       uint32_t        surface4_upper_bound;
+       uint32_t        surface5_info;
+       uint32_t        surface5_lower_bound;
+       uint32_t        surface5_upper_bound;
+       uint32_t        surface6_info;
+       uint32_t        surface6_lower_bound;
+       uint32_t        surface6_upper_bound;
+       uint32_t        surface7_info;
+       uint32_t        surface7_lower_bound;
+       uint32_t        surface7_upper_bound;
+       /* crtc */
+       uint32_t        crtc_gen_cntl;
+       uint32_t        crtc_ext_cntl;
+       uint32_t        crtc_h_total_disp;
+       uint32_t        crtc_h_sync_strt_wid;
+       uint32_t        crtc_v_total_disp;
+       uint32_t        crtc_v_sync_strt_wid;
+       uint32_t        crtc_offset;
+       uint32_t        crtc_offset_cntl;
+       uint32_t        crtc_pitch;
+       uint32_t        crtc_more_cntl;
+       uint32_t        crtc_tile_x0_y0;
+       uint32_t        fp_h_sync_strt_wid;
+       uint32_t        fp_v_sync_strt_wid;
+       uint32_t        fp_crtc_h_total_disp;
+       uint32_t        fp_crtc_v_total_disp;
+       /* pll */
+       uint32_t        clock_cntl_index;
+       uint32_t        ppll_cntl;
+       uint32_t        ppll_ref_div;
+       uint32_t        ppll_div_0;
+       uint32_t        ppll_div_1;
+       uint32_t        ppll_div_2;
+       uint32_t        ppll_div_3;
+       uint32_t        vclk_ecp_cntl;
+       uint32_t        htotal_cntl;
+       /* dac */
+       uint32_t        dac_cntl;
+       uint32_t        dac_cntl2;
+       uint32_t        dac_ext_cntl;
+       uint32_t        disp_misc_cntl;
+       uint32_t        dac_macro_cntl;
+       uint32_t        disp_pwr_man;
+       uint32_t        disp_merge_cntl;
+       uint32_t        disp_output_cntl;
+       uint32_t        disp2_merge_cntl;
+       uint32_t        dac_embedded_sync_cntl;
+       uint32_t        dac_broad_pulse;
+       uint32_t        dac_skew_clks;
+       uint32_t        dac_incr;
+       uint32_t        dac_neg_sync_level;
+       uint32_t        dac_pos_sync_level;
+       uint32_t        dac_blank_level;
+       uint32_t        dac_sync_equalization;
+       uint32_t        tv_dac_cntl;
+       uint32_t        tv_master_cntl;
+};
+
+struct drm_radeon_private {
+       /* driver family specific functions */
+       int (*bus_finish)(struct drm_device *dev);
+       int (*bus_init)(struct drm_device *dev);
+       void (*bus_restore)(struct drm_device *dev, struct radeon_state *state);
+       void (*bus_save)(struct drm_device *dev, struct radeon_state *state);
+       struct drm_ttm_backend *(*create_ttm)(struct drm_device *dev);
+       void (*irq_emit)(struct drm_device *dev);
+       void (*flush_cache)(struct drm_device *dev);
+       /* bus informations */
+       void                        *bus;
+       uint32_t                    bus_type;
+       /* cp */
+       uint32_t                    ring_buffer_size;
+       uint32_t                    ring_rptr;
+       uint32_t                    ring_wptr;
+       uint32_t                    ring_mask;
+       int                         ring_free;
+       uint32_t                    ring_tail_mask;
+       uint32_t                    write_back_area_size;
+       struct drm_buffer_object    *ring_buffer_object;
+       struct drm_bo_kmap_obj      ring_buffer_map;
+       uint32_t                    *ring_buffer;
+       uint32_t                    *write_back_area;
+       const uint32_t              *microcode;
+       /* card family */
+       uint32_t                    usec_timeout;
+       uint32_t                    family;
+       struct radeon_ms_output     *outputs[RADEON_MAX_OUTPUTS];
+       struct radeon_ms_connector  *connectors[RADEON_MAX_CONNECTORS];
+       /* drm map (MMIO, FB) */
+       struct drm_map              mmio;
+       struct drm_map              vram;
+       /* gpu address space */
+       uint32_t                    gpu_vram_size;
+       uint32_t                    gpu_vram_start;
+       uint32_t                    gpu_vram_end;
+       uint32_t                    gpu_gart_size;
+       uint32_t                    gpu_gart_start;
+       uint32_t                    gpu_gart_end;
+       /* state of the card when module was loaded */
+       struct radeon_state         load_state;
+       /* state the driver wants */
+       struct radeon_state         driver_state;
+       /* last emitted fence */
+       uint32_t                    fence_id_last;
+       uint32_t                    fence_reg;
+       /* when doing gpu stop we save here current state */
+       uint32_t                    crtc_ext_cntl;
+       uint32_t                    crtc_gen_cntl;
+       uint32_t                    crtc2_gen_cntl;
+       uint32_t                    ov0_scale_cntl;
+       /* bool & type on the hw */
+       uint8_t                     crtc1_dpms;
+       uint8_t                     crtc2_dpms;
+       uint8_t                     restore_state;
+       uint8_t                     cp_ready;
+       uint8_t                     bus_ready;
+       uint8_t                     write_back;
+       /* abstract asic specific structures */
+       struct radeon_ms_rom        rom;
+       struct radeon_ms_properties properties;
+};
+
+
+/* radeon_ms_bo.c */
+int radeon_ms_bo_get_gpu_addr(struct drm_device *dev,
+                             struct drm_bo_mem_reg *mem,
+                             uint32_t *gpu_addr);
+int radeon_ms_bo_move(struct drm_buffer_object * bo, int evict,
+                     int no_wait, struct drm_bo_mem_reg * new_mem);
+struct drm_ttm_backend *radeon_ms_create_ttm_backend(struct drm_device * dev);
+uint64_t radeon_ms_evict_flags(struct drm_buffer_object *bo);
+int radeon_ms_init_mem_type(struct drm_device * dev, uint32_t type,
+                           struct drm_mem_type_manager * man);
+int radeon_ms_invalidate_caches(struct drm_device * dev, uint64_t flags);
+void radeon_ms_ttm_flush(struct drm_ttm *ttm);
+
+/* radeon_ms_bus.c */
+int radeon_ms_agp_finish(struct drm_device *dev);
+int radeon_ms_agp_init(struct drm_device *dev);
+void radeon_ms_agp_restore(struct drm_device *dev, struct radeon_state *state);
+void radeon_ms_agp_save(struct drm_device *dev, struct radeon_state *state);
+struct drm_ttm_backend *radeon_ms_pcie_create_ttm(struct drm_device *dev);
+int radeon_ms_pcie_finish(struct drm_device *dev);
+int radeon_ms_pcie_init(struct drm_device *dev);
+void radeon_ms_pcie_restore(struct drm_device *dev, struct radeon_state *state);
+void radeon_ms_pcie_save(struct drm_device *dev, struct radeon_state *state);
+
+/* radeon_ms_combios.c */
+int radeon_ms_combios_get_properties(struct drm_device *dev);
+int radeon_ms_connectors_from_combios(struct drm_device *dev);
+int radeon_ms_outputs_from_combios(struct drm_device *dev);
+
+/* radeon_ms_compat.c */
+long radeon_ms_compat_ioctl(struct file *filp, unsigned int cmd,
+                           unsigned long arg);
+
+/* radeon_ms_cp.c */
+int radeon_ms_cp_finish(struct drm_device *dev);
+int radeon_ms_cp_init(struct drm_device *dev);
+void radeon_ms_cp_restore(struct drm_device *dev, struct radeon_state *state);
+void radeon_ms_cp_save(struct drm_device *dev, struct radeon_state *state);
+void radeon_ms_cp_stop(struct drm_device *dev);
+int radeon_ms_cp_wait(struct drm_device *dev, int n);
+int radeon_ms_ring_emit(struct drm_device *dev, uint32_t *cmd, uint32_t count);
+
+/* radeon_ms_crtc.c */
+int radeon_ms_crtc_create(struct drm_device *dev, int crtc);
+void radeon_ms_crtc1_restore(struct drm_device *dev,
+                            struct radeon_state *state);
+void radeon_ms_crtc1_save(struct drm_device *dev, struct radeon_state *state);
+
+/* radeon_ms_dac.c */
+int radeon_ms_dac1_initialize(struct radeon_ms_output *output);
+enum drm_output_status radeon_ms_dac1_detect(struct radeon_ms_output *output);
+void radeon_ms_dac1_dpms(struct radeon_ms_output *output, int mode);
+int radeon_ms_dac1_get_modes(struct radeon_ms_output *output);
+bool radeon_ms_dac1_mode_fixup(struct radeon_ms_output *output,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode);
+int radeon_ms_dac1_mode_set(struct radeon_ms_output *output,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode);
+void radeon_ms_dac1_restore(struct radeon_ms_output *output,
+               struct radeon_state *state);
+void radeon_ms_dac1_save(struct radeon_ms_output *output,
+               struct radeon_state *state);
+int radeon_ms_dac2_initialize(struct radeon_ms_output *output);
+enum drm_output_status radeon_ms_dac2_detect(struct radeon_ms_output *output);
+void radeon_ms_dac2_dpms(struct radeon_ms_output *output, int mode);
+int radeon_ms_dac2_get_modes(struct radeon_ms_output *output);
+bool radeon_ms_dac2_mode_fixup(struct radeon_ms_output *output,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode);
+int radeon_ms_dac2_mode_set(struct radeon_ms_output *output,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode);
+void radeon_ms_dac2_restore(struct radeon_ms_output *output,
+               struct radeon_state *state);
+void radeon_ms_dac2_save(struct radeon_ms_output *output,
+               struct radeon_state *state);
+
+/* radeon_ms_drm.c */
+int radeon_ms_driver_dma_ioctl(struct drm_device *dev, void *data,
+                              struct drm_file *file_priv);
+void radeon_ms_driver_lastclose(struct drm_device * dev);
+int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags);
+int radeon_ms_driver_open(struct drm_device * dev, struct drm_file *file_priv);
+int radeon_ms_driver_unload(struct drm_device *dev);
+
+/* radeon_ms_exec.c */
+int radeon_ms_execbuffer(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+
+/* radeon_ms_family.c */
+int radeon_ms_family_init(struct drm_device *dev);
+
+/* radeon_ms_fence.c */
+int radeon_ms_fence_emit_sequence(struct drm_device *dev, uint32_t class,
+                                 uint32_t flags, uint32_t *sequence,
+                                 uint32_t *native_type);
+void radeon_ms_fence_handler(struct drm_device * dev);
+int radeon_ms_fence_has_irq(struct drm_device *dev, uint32_t class,
+                           uint32_t flags);
+int radeon_ms_fence_types(struct drm_buffer_object *bo,
+                         uint32_t * class, uint32_t * type);
+void radeon_ms_poke_flush(struct drm_device * dev, uint32_t class);
+
+/* radeon_ms_fb.c */
+int radeonfb_probe(struct drm_device *dev, struct drm_crtc *crtc);
+int radeonfb_remove(struct drm_device *dev, struct drm_crtc *crtc);
+
+/* radeon_ms_gpu.c */
+int radeon_ms_gpu_initialize(struct drm_device *dev);
+void radeon_ms_gpu_dpms(struct drm_device *dev);
+void radeon_ms_gpu_flush(struct drm_device *dev);
+void radeon_ms_gpu_restore(struct drm_device *dev, struct radeon_state *state);
+void radeon_ms_gpu_save(struct drm_device *dev, struct radeon_state *state);
+int radeon_ms_wait_for_idle(struct drm_device *dev);
+
+/* radeon_ms_i2c.c */
+void radeon_ms_i2c_destroy(struct radeon_ms_i2c *i2c);
+struct radeon_ms_i2c *radeon_ms_i2c_create(struct drm_device *dev,
+                                          const uint32_t reg,
+                                          const char *name);
+
+/* radeon_ms_irq.c */
+void radeon_ms_irq_emit(struct drm_device *dev);
+irqreturn_t radeon_ms_irq_handler(DRM_IRQ_ARGS);
+void radeon_ms_irq_preinstall(struct drm_device * dev);
+int radeon_ms_irq_postinstall(struct drm_device * dev);
+int radeon_ms_irq_init(struct drm_device *dev);
+void radeon_ms_irq_restore(struct drm_device *dev, struct radeon_state *state);
+void radeon_ms_irq_save(struct drm_device *dev, struct radeon_state *state);
+void radeon_ms_irq_uninstall(struct drm_device * dev);
+
+/* radeon_ms_output.c */
+void radeon_ms_connectors_destroy(struct drm_device *dev);
+int radeon_ms_connectors_from_properties(struct drm_device *dev);
+int radeon_ms_connectors_from_rom(struct drm_device *dev);
+void radeon_ms_outputs_destroy(struct drm_device *dev);
+int radeon_ms_outputs_from_properties(struct drm_device *dev);
+int radeon_ms_outputs_from_rom(struct drm_device *dev);
+void radeon_ms_outputs_restore(struct drm_device *dev,
+               struct radeon_state *state);
+void radeon_ms_outputs_save(struct drm_device *dev, struct radeon_state *state);
+
+/* radeon_ms_properties.c */
+int radeon_ms_properties_init(struct drm_device *dev);
+
+/* radeon_ms_rom.c */
+int radeon_ms_rom_get_properties(struct drm_device *dev);
+int radeon_ms_rom_init(struct drm_device *dev);
+
+/* radeon_ms_state.c */
+void radeon_ms_state_save(struct drm_device *dev, struct radeon_state *state);
+void radeon_ms_state_restore(struct drm_device *dev,
+                            struct radeon_state *state);
+
+
+/* packect stuff **************************************************************/
+#define RADEON_CP_PACKET0                               0x00000000
+#define CP_PACKET0(reg, n)                                             \
+       (RADEON_CP_PACKET0 | ((n) << 16) | ((reg) >> 2))
+#define CP_PACKET3_CNTL_BITBLT_MULTI                    0xC0009B00
+#    define GMC_SRC_PITCH_OFFSET_CNTL                       (1    <<  0)
+#    define GMC_DST_PITCH_OFFSET_CNTL                       (1    <<  1)
+#    define GMC_BRUSH_NONE                                  (15   <<  4)
+#    define GMC_SRC_DATATYPE_COLOR                          (3    << 12)
+#    define ROP3_S                                          0x00cc0000
+#    define DP_SRC_SOURCE_MEMORY                            (2    << 24)
+#    define GMC_CLR_CMP_CNTL_DIS                            (1    << 28)
+#    define GMC_WR_MSK_DIS                                  (1    << 30)
+
+/* helper macro & functions ***************************************************/
+#define REG_S(rn, bn, v)    (((v) << rn##__##bn##__SHIFT) & rn##__##bn##__MASK)
+#define REG_G(rn, bn, v)    (((v) & rn##__##bn##__MASK) >> rn##__##bn##__SHIFT)
+#define MMIO_R(rid)         mmio_read(dev_priv, rid)
+#define MMIO_W(rid, v)      mmio_write(dev_priv, rid, v)
+#define PCIE_R(rid)         pcie_read(dev_priv, rid)
+#define PCIE_W(rid, v)      pcie_write(dev_priv, rid, v)
+#define PPLL_R(rid)         pll_read(dev_priv, rid)
+#define PPLL_W(rid, v)      pll_write(dev_priv, rid, v)
+
+static __inline__ uint32_t mmio_read(struct drm_radeon_private *dev_priv,
+                                    uint32_t offset)
+{
+       return DRM_READ32(&dev_priv->mmio, offset);
+}
+
+
+static __inline__ void mmio_write(struct drm_radeon_private *dev_priv,
+                                 uint32_t offset, uint32_t v)
+{
+       DRM_WRITE32(&dev_priv->mmio, offset, v);
+}
+
+static __inline__ uint32_t pcie_read(struct drm_radeon_private *dev_priv,
+                                    uint32_t offset)
+{
+       MMIO_W(PCIE_INDEX, REG_S(PCIE_INDEX, PCIE_INDEX, offset));
+       return MMIO_R(PCIE_DATA);
+}
+
+static __inline__ void pcie_write(struct drm_radeon_private *dev_priv,
+                                 uint32_t offset, uint32_t v)
+{
+       MMIO_W(PCIE_INDEX, REG_S(PCIE_INDEX, PCIE_INDEX, offset));
+       MMIO_W(PCIE_DATA, v);
+}
+
+static __inline__ void pll_index_errata(struct drm_radeon_private *dev_priv)
+{
+       uint32_t tmp, save;
+
+       /* This workaround is necessary on rv200 and RS200 or PLL
+        * reads may return garbage (among others...)
+        */
+       if (dev_priv->properties.pll_dummy_reads) {
+               tmp = MMIO_R(CLOCK_CNTL_DATA);
+               tmp = MMIO_R(CRTC_GEN_CNTL);
+       }
+       /* This function is required to workaround a hardware bug in some (all?)
+        * revisions of the R300.  This workaround should be called after every
+        * CLOCK_CNTL_INDEX register access.  If not, register reads afterward
+        * may not be correct.
+        */
+       if (dev_priv->properties.pll_r300_errata) {
+               tmp = save = MMIO_R(CLOCK_CNTL_INDEX);
+               tmp = tmp & ~CLOCK_CNTL_INDEX__PLL_ADDR__MASK;
+               tmp = tmp & ~CLOCK_CNTL_INDEX__PLL_WR_EN;
+               MMIO_W(CLOCK_CNTL_INDEX, tmp);
+               tmp = MMIO_R(CLOCK_CNTL_DATA);
+               MMIO_W(CLOCK_CNTL_INDEX, save);
+       }
+}
+
+static __inline__ void pll_data_errata(struct drm_radeon_private *dev_priv)
+{
+       /* This workarounds is necessary on RV100, RS100 and RS200 chips
+        * or the chip could hang on a subsequent access
+        */
+       if (dev_priv->properties.pll_delay) {
+               /* we can't deal with posted writes here ... */
+               udelay(5000);
+       }
+}
+
+static __inline__ uint32_t pll_read(struct drm_radeon_private *dev_priv,
+                                   uint32_t offset)
+{
+       uint32_t clock_cntl_index = dev_priv->driver_state.clock_cntl_index;
+       uint32_t data;
+
+       clock_cntl_index &= ~CLOCK_CNTL_INDEX__PLL_ADDR__MASK;
+       clock_cntl_index |= REG_S(CLOCK_CNTL_INDEX, PLL_ADDR, offset);
+       MMIO_W(CLOCK_CNTL_INDEX, clock_cntl_index);
+       pll_index_errata(dev_priv);
+       data = MMIO_R(CLOCK_CNTL_DATA);
+       pll_data_errata(dev_priv);
+       return data;
+}
+
+static __inline__ void pll_write(struct drm_radeon_private *dev_priv,
+                                uint32_t offset, uint32_t value)
+{
+       uint32_t clock_cntl_index = dev_priv->driver_state.clock_cntl_index;
+
+       clock_cntl_index &= ~CLOCK_CNTL_INDEX__PLL_ADDR__MASK;
+       clock_cntl_index |= REG_S(CLOCK_CNTL_INDEX, PLL_ADDR, offset);
+       clock_cntl_index |= CLOCK_CNTL_INDEX__PLL_WR_EN;
+       MMIO_W(CLOCK_CNTL_INDEX, clock_cntl_index);
+       pll_index_errata(dev_priv);
+       MMIO_W(CLOCK_CNTL_DATA, value);
+       pll_data_errata(dev_priv);
+}
+
+#endif
diff --git a/shared-core/radeon_ms_bo.c b/shared-core/radeon_ms_bo.c
new file mode 100644 (file)
index 0000000..6d9a97c
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2007 Dave Airlie
+ * Copyright 2007 Jérôme Glisse
+ * 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 the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, 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 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
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ */
+/*
+ * Authors:
+ *    Dave Airlie <airlied@linux.ie>
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#include "drmP.h"
+#include "drm.h"
+
+#include "radeon_ms.h"
+
+void radeon_ms_bo_copy_blit(struct drm_device *dev,
+                           uint32_t src_offset,
+                           uint32_t dst_offset,
+                           uint32_t pages)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       uint32_t num_pages, stride, c;
+       uint32_t offset_inc = 0;
+       uint32_t cmd[7];
+
+       if (!dev_priv) {
+               return;
+       }
+
+       /* radeon limited to 16320=255*64 bytes per row so copy at
+        * most 2 pages */
+       num_pages = 2;
+       stride = ((num_pages * PAGE_SIZE) / 64) & 0xff;
+       while(pages > 0) {
+               if (num_pages > pages) {
+                       num_pages = pages;
+                       stride = ((num_pages * PAGE_SIZE) / 64) & 0xff;
+               }
+               c = pages / num_pages;
+               if (c >= 8192) {
+                       c = 8191;
+               }
+               cmd[0] = CP_PACKET3_CNTL_BITBLT_MULTI | (5 << 16);
+               cmd[1] = GMC_SRC_PITCH_OFFSET_CNTL |
+                        GMC_DST_PITCH_OFFSET_CNTL |
+                        GMC_BRUSH_NONE |
+                        (0x6 << 8) |
+                        GMC_SRC_DATATYPE_COLOR |
+                        ROP3_S |
+                        DP_SRC_SOURCE_MEMORY |
+                        GMC_CLR_CMP_CNTL_DIS |
+                        GMC_WR_MSK_DIS;
+               cmd[2] = (stride << 22) | (src_offset >> 10);
+               cmd[3] = (stride << 22) | (dst_offset >> 10);
+               cmd[4] = (0 << 16) | 0;
+               cmd[5] = (0 << 16) | 0;
+               cmd[6] = ((stride * 16) << 16) | c;
+               radeon_ms_ring_emit(dev, cmd, 7);
+               offset_inc = num_pages * c * PAGE_SIZE;
+               src_offset += offset_inc;
+               dst_offset += offset_inc;
+               pages -= num_pages * c;
+       }
+       /* wait for 2d engine to go busy so wait_until stall */
+       for (c = 0; c < dev_priv->usec_timeout; c++) {
+               uint32_t status = MMIO_R(RBBM_STATUS);
+               if ((RBBM_STATUS__E2_BUSY & status) ||
+                   (RBBM_STATUS__CBA2D_BUSY & status)) {
+                       DRM_INFO("[radeon_ms] RBBM_STATUS 0x%08X\n", status);
+                       break;
+               }
+               DRM_UDELAY(1);
+       }
+       /* Sync everything up */
+       cmd[0] = CP_PACKET0(WAIT_UNTIL, 0);
+       cmd[1] = WAIT_UNTIL__WAIT_2D_IDLECLEAN |
+                WAIT_UNTIL__WAIT_HOST_IDLECLEAN;
+       radeon_ms_ring_emit(dev, cmd, 2);
+       return;
+}
+
+static int radeon_ms_bo_move_blit(struct drm_buffer_object *bo,
+                                 int evict, int no_wait,
+                                 struct drm_bo_mem_reg *new_mem)
+{
+       struct drm_device *dev = bo->dev;
+       struct drm_bo_mem_reg *old_mem = &bo->mem;
+       uint32_t gpu_src_addr;
+       uint32_t gpu_dst_addr;
+       int ret;
+
+       ret = radeon_ms_bo_get_gpu_addr(dev, old_mem, &gpu_src_addr);
+       if (ret) {
+               return ret;
+       }
+       ret = radeon_ms_bo_get_gpu_addr(dev, new_mem, &gpu_dst_addr);
+       if (ret) {
+               return ret;
+       }
+
+       radeon_ms_bo_copy_blit(bo->dev,
+                              gpu_src_addr,
+                              gpu_dst_addr,
+                              new_mem->num_pages);
+       
+       ret = drm_bo_move_accel_cleanup(bo, evict, no_wait, 0,
+                                        DRM_FENCE_TYPE_EXE |
+                                        DRM_RADEON_FENCE_TYPE_RW,
+                                        DRM_RADEON_FENCE_FLAG_FLUSHED,
+                                        new_mem);
+       return ret;
+}
+
+static int radeon_ms_bo_move_flip(struct drm_buffer_object *bo,
+                                 int evict, int no_wait,
+                                 struct drm_bo_mem_reg *new_mem)
+{
+       struct drm_device *dev = bo->dev;
+       struct drm_bo_mem_reg tmp_mem;
+       int ret;
+
+       tmp_mem = *new_mem;
+       tmp_mem.mm_node = NULL;
+       tmp_mem.flags = DRM_BO_FLAG_MEM_TT |
+                      DRM_BO_FLAG_CACHED |
+                      DRM_BO_FLAG_FORCE_CACHING;
+       ret = drm_bo_mem_space(bo, &tmp_mem, no_wait);
+       if (ret) {
+               return ret;
+       }
+
+       ret = drm_ttm_bind(bo->ttm, &tmp_mem);
+       if (ret) {
+               goto out_cleanup;
+       }
+       ret = radeon_ms_bo_move_blit(bo, 1, no_wait, &tmp_mem);
+       if (ret) {
+               goto out_cleanup;
+       }
+       ret = drm_bo_move_ttm(bo, evict, no_wait, new_mem);
+out_cleanup:
+       if (tmp_mem.mm_node) {
+               mutex_lock(&dev->struct_mutex);
+               if (tmp_mem.mm_node != bo->pinned_node)
+                       drm_mm_put_block(tmp_mem.mm_node);
+               tmp_mem.mm_node = NULL;
+               mutex_unlock(&dev->struct_mutex);
+       }
+       return ret;
+}
+
+int radeon_ms_bo_get_gpu_addr(struct drm_device *dev,
+                             struct drm_bo_mem_reg *mem,
+                             uint32_t *gpu_addr)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       *gpu_addr = mem->mm_node->start << PAGE_SHIFT;
+       switch (mem->flags & DRM_BO_MASK_MEM) {
+       case DRM_BO_FLAG_MEM_TT:
+               *gpu_addr +=  dev_priv->gpu_gart_start;
+               DRM_INFO("[radeon_ms] GPU TT: 0x%08X\n", *gpu_addr);
+               break;
+       case DRM_BO_FLAG_MEM_VRAM:
+               *gpu_addr +=  dev_priv->gpu_vram_start;
+               DRM_INFO("[radeon_ms] GPU VRAM: 0x%08X\n", *gpu_addr);
+               break;
+       default:
+               DRM_ERROR("[radeon_ms] memory not accessible by GPU\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int radeon_ms_bo_move(struct drm_buffer_object *bo, int evict,
+                  int no_wait, struct drm_bo_mem_reg *new_mem)
+{
+       struct drm_bo_mem_reg *old_mem = &bo->mem;
+       if (old_mem->mem_type == DRM_BO_MEM_LOCAL) {
+               return drm_bo_move_memcpy(bo, evict, no_wait, new_mem);
+       } else if (new_mem->mem_type == DRM_BO_MEM_LOCAL) {
+               if (radeon_ms_bo_move_flip(bo, evict, no_wait, new_mem))
+                       return drm_bo_move_memcpy(bo, evict, no_wait, new_mem);
+       } else {
+               if (radeon_ms_bo_move_blit(bo, evict, no_wait, new_mem))
+                       return drm_bo_move_memcpy(bo, evict, no_wait, new_mem);
+       }
+       return 0;
+}
+
+struct drm_ttm_backend *radeon_ms_create_ttm_backend(struct drm_device * dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       if (dev_priv && dev_priv->create_ttm)
+               return dev_priv->create_ttm(dev);
+       return NULL;
+}
+
+uint64_t radeon_ms_evict_flags(struct drm_buffer_object *bo)
+{
+       switch (bo->mem.mem_type) {
+       case DRM_BO_MEM_LOCAL:
+       case DRM_BO_MEM_TT:
+               return DRM_BO_FLAG_MEM_LOCAL;
+       case DRM_BO_MEM_VRAM:
+               if (bo->mem.num_pages > 128)
+                       return DRM_BO_MEM_TT;
+               else
+                       return DRM_BO_MEM_LOCAL;
+       default:
+               return DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_CACHED;
+       }
+}
+
+int radeon_ms_init_mem_type(struct drm_device * dev, uint32_t type,
+                           struct drm_mem_type_manager * man)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       switch (type) {
+       case DRM_BO_MEM_LOCAL:
+               man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE |
+                   _DRM_FLAG_MEMTYPE_CACHED;
+               man->drm_bus_maptype = 0;
+               break;
+       case DRM_BO_MEM_VRAM:
+               man->flags =  _DRM_FLAG_MEMTYPE_FIXED |
+                             _DRM_FLAG_MEMTYPE_MAPPABLE |
+                             _DRM_FLAG_NEEDS_IOREMAP;
+               man->io_addr = NULL;
+               man->drm_bus_maptype = _DRM_FRAME_BUFFER;
+               man->io_offset = dev_priv->vram.offset;
+               man->io_size = dev_priv->vram.size;
+               break;
+       case DRM_BO_MEM_TT:
+               if (!dev_priv->bus_ready) {
+                       DRM_ERROR("Bus isn't initialized while "
+                                 "intializing TT memory type\n");
+                       return -EINVAL;
+               }
+               switch(dev_priv->bus_type) {
+               case RADEON_AGP:
+                       if (!(drm_core_has_AGP(dev) && dev->agp)) {
+                               DRM_ERROR("AGP is not enabled for memory "
+                                         "type %u\n", (unsigned)type);
+                               return -EINVAL;
+                       }
+                       man->io_offset = dev->agp->agp_info.aper_base;
+                       man->io_size = dev->agp->agp_info.aper_size *
+                                      1024 * 1024;
+                       man->io_addr = NULL;
+                       man->flags = _DRM_FLAG_MEMTYPE_MAPPABLE |
+                                    _DRM_FLAG_MEMTYPE_CSELECT |
+                                    _DRM_FLAG_NEEDS_IOREMAP;
+                       man->drm_bus_maptype = _DRM_AGP;
+                       man->gpu_offset = 0;
+                       break;
+               default:
+                       man->io_offset = dev_priv->gpu_gart_start;
+                       man->io_size = dev_priv->gpu_gart_size;
+                       man->io_addr = NULL;
+                       man->flags = _DRM_FLAG_MEMTYPE_CSELECT |
+                                    _DRM_FLAG_MEMTYPE_MAPPABLE |
+                                    _DRM_FLAG_MEMTYPE_CMA;
+                       man->drm_bus_maptype = _DRM_SCATTER_GATHER;
+                       break;
+               }
+               break;
+       default:
+               DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int radeon_ms_invalidate_caches(struct drm_device * dev, uint64_t flags)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       dev_priv->flush_cache(dev);
+       return 0;
+}
+
+void radeon_ms_ttm_flush(struct drm_ttm *ttm)
+{
+       if (!ttm)
+               return;
+
+       DRM_MEMORYBARRIER();
+}
diff --git a/shared-core/radeon_ms_bus.c b/shared-core/radeon_ms_bus.c
new file mode 100644 (file)
index 0000000..ed8fb21
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * Copyright 2007 Alex Deucher
+ * Copyright 2007 Dave Airlie
+ * 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 the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, 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 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
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ */
+/*
+ * Authors:
+ *    Dave Airlie <airlied@linux.ie>
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_ms.h"
+
+struct radeon_pcie {
+       uint32_t                    gart_table_size;
+       struct drm_buffer_object    *gart_table_object;
+       volatile uint32_t           *gart_table;
+       struct drm_device           *dev;
+       unsigned long               page_last;
+};
+
+struct radeon_pcie_gart {
+       struct drm_ttm_backend  backend;
+       struct radeon_pcie      *pcie;
+       unsigned long           page_first;
+       struct page             **pages;
+       struct page             *dummy_read_page;
+       unsigned long           num_pages;
+       int                     populated;
+       int                     bound;
+};
+
+static int pcie_ttm_bind(struct drm_ttm_backend *backend,
+                        struct drm_bo_mem_reg *bo_mem);
+static void pcie_ttm_clear(struct drm_ttm_backend *backend);
+static void pcie_ttm_destroy(struct drm_ttm_backend *backend);
+static int pcie_ttm_needs_ub_cache_adjust(struct drm_ttm_backend *backend);
+static int pcie_ttm_populate(struct drm_ttm_backend *backend,
+                            unsigned long num_pages, struct page **pages,
+                            struct page *dummy_read_page);
+static int pcie_ttm_unbind(struct drm_ttm_backend *backend);
+
+static struct drm_ttm_backend_func radeon_pcie_gart_ttm_backend = 
+{
+       .needs_ub_cache_adjust = pcie_ttm_needs_ub_cache_adjust,
+       .populate = pcie_ttm_populate,
+       .clear = pcie_ttm_clear,
+       .bind = pcie_ttm_bind,
+       .unbind = pcie_ttm_unbind,
+       .destroy =  pcie_ttm_destroy,
+};
+
+static void pcie_gart_flush(struct radeon_pcie *pcie)
+{
+       struct drm_device *dev;
+       struct drm_radeon_private *dev_priv;
+       uint32_t flush;
+
+       if (pcie == NULL) {
+               return;
+       }
+       dev = pcie->dev;
+       dev_priv = dev->dev_private;
+       flush = dev_priv->driver_state.pcie_tx_gart_cntl;
+       flush |= PCIE_TX_GART_CNTL__GART_INVALIDATE_TLB;
+       PCIE_W(PCIE_TX_GART_CNTL, flush);
+       PCIE_W(PCIE_TX_GART_CNTL, dev_priv->driver_state.pcie_tx_gart_cntl);
+}
+
+static __inline__ uint32_t pcie_gart_get_page_base(struct radeon_pcie *pcie,
+                                                  unsigned long page)
+{
+       if (pcie == NULL || pcie->gart_table == NULL) {
+               return 0;
+       }
+       return ((pcie->gart_table[page] & (~0xC)) << 8);
+}
+
+static __inline__ void pcie_gart_set_page_base(struct radeon_pcie *pcie,
+                                              unsigned long page,
+                                              uint32_t page_base)
+{
+       if (pcie == NULL || pcie->gart_table == NULL) {
+               return;
+       }
+       pcie->gart_table[page] = cpu_to_le32((page_base >> 8) | 0xC);
+}
+
+static int pcie_ttm_bind(struct drm_ttm_backend *backend,
+                        struct drm_bo_mem_reg *bo_mem)
+{
+       struct radeon_pcie_gart *pcie_gart;
+       unsigned long page_first;
+       unsigned long page_last;
+       unsigned long page, i;
+       uint32_t page_base;
+
+       pcie_gart = container_of(backend, struct radeon_pcie_gart, backend);
+       page = page_first = bo_mem->mm_node->start;
+       page_last = page_first + pcie_gart->num_pages;
+       if (page_first >= pcie_gart->pcie->page_last ||
+           page_last >= pcie_gart->pcie->page_last)
+           return -EINVAL;
+        while (page < page_last) {
+               if (pcie_gart_get_page_base(pcie_gart->pcie, page)) {
+                       return -EBUSY;
+               }
+                page++;
+        }
+
+        for (i = 0, page = page_first; i < pcie_gart->num_pages; i++, page++) {
+               struct page *cur_page = pcie_gart->pages[i];
+
+               if (!page) {
+                       cur_page = pcie_gart->dummy_read_page;
+               }
+                /* write value */
+               page_base = page_to_phys(cur_page);
+               pcie_gart_set_page_base(pcie_gart->pcie, page, page_base);
+        }
+       DRM_MEMORYBARRIER();
+       pcie_gart_flush(pcie_gart->pcie);
+       pcie_gart->bound = 1;
+       pcie_gart->page_first = page_first;
+       return 0;
+}
+
+static void pcie_ttm_clear(struct drm_ttm_backend *backend)
+{
+       struct radeon_pcie_gart *pcie_gart;
+
+       pcie_gart = container_of(backend, struct radeon_pcie_gart, backend);
+       if (pcie_gart->pages) {
+               backend->func->unbind(backend);
+               pcie_gart->pages = NULL;
+       }
+       pcie_gart->num_pages = 0;
+}
+
+static void pcie_ttm_destroy(struct drm_ttm_backend *backend)
+{
+       struct radeon_pcie_gart *pcie_gart;
+
+       if (backend == NULL) {
+               return;
+       }
+       pcie_gart = container_of(backend, struct radeon_pcie_gart, backend);
+       if (pcie_gart->pages) {
+               backend->func->clear(backend);
+       }
+       drm_ctl_free(pcie_gart, sizeof(*pcie_gart), DRM_MEM_TTM);
+}
+
+static int pcie_ttm_needs_ub_cache_adjust(struct drm_ttm_backend *backend)
+{
+       return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1);
+}
+
+static int pcie_ttm_populate(struct drm_ttm_backend *backend,
+                            unsigned long num_pages, struct page **pages,
+                            struct page *dummy_read_page)
+{
+       struct radeon_pcie_gart *pcie_gart;
+
+       pcie_gart = container_of(backend, struct radeon_pcie_gart, backend);
+       pcie_gart->pages = pages;
+       pcie_gart->num_pages = num_pages;
+       pcie_gart->populated = 1;
+       return 0;
+}
+
+static int pcie_ttm_unbind(struct drm_ttm_backend *backend)
+{
+       struct radeon_pcie_gart *pcie_gart;
+       unsigned long page, i;
+
+       pcie_gart = container_of(backend, struct radeon_pcie_gart, backend);
+       if (pcie_gart->bound != 1 || pcie_gart->pcie->gart_table == NULL) {
+               return -EINVAL;
+       }
+       for (i = 0, page = pcie_gart->page_first; i < pcie_gart->num_pages;
+            i++, page++) {
+               pcie_gart->pcie->gart_table[page] = 0;
+       }
+       pcie_gart_flush(pcie_gart->pcie);
+       pcie_gart->bound = 0;
+       pcie_gart->page_first = 0;
+       return 0;
+}
+
+int radeon_ms_agp_finish(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       if (!dev_priv->bus_ready) {
+               return 0;
+       }
+       dev_priv->bus_ready = 0;
+       drm_agp_release(dev);
+       return 0;
+}
+
+int radeon_ms_agp_init(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+       struct drm_agp_mode mode;
+       uint32_t agp_status;
+       int ret;
+
+       dev_priv->bus_ready = -1;
+       if (dev->agp == NULL) {
+               DRM_ERROR("[radeon_ms] can't initialize AGP\n");
+               return -EINVAL;
+       }
+       ret = drm_agp_acquire(dev);
+       if (ret) {
+               DRM_ERROR("[radeon_ms] error failed to acquire agp\n");
+               return ret;
+       }
+       agp_status = MMIO_R(AGP_STATUS);
+       if ((AGP_STATUS__MODE_AGP30 & agp_status)) {
+               mode.mode = AGP_STATUS__RATE4X;
+       } else {
+               mode.mode = AGP_STATUS__RATE2X_8X;
+       }
+       ret = drm_agp_enable(dev, mode);
+       if (ret) {
+               DRM_ERROR("[radeon_ms] error failed to enable agp\n");
+               return ret;
+       }
+       state->agp_command = MMIO_R(AGP_COMMAND) | AGP_COMMAND__AGP_EN;
+       state->agp_command &= ~AGP_COMMAND__FW_EN;
+       state->agp_command &= ~AGP_COMMAND__MODE_4G_EN;
+       state->aic_ctrl = 0;
+       state->agp_base = REG_S(AGP_BASE, AGP_BASE_ADDR, dev->agp->base);
+       state->agp_base_2 = 0;
+       state->bus_cntl = MMIO_R(BUS_CNTL);
+       state->bus_cntl &= ~BUS_CNTL__BUS_MASTER_DIS;
+       state->mc_agp_location =
+               REG_S(MC_AGP_LOCATION, MC_AGP_START,
+                               dev_priv->gpu_gart_start >> 16) |
+               REG_S(MC_AGP_LOCATION, MC_AGP_TOP,
+                               dev_priv->gpu_gart_end >> 16);
+       DRM_INFO("[radeon_ms] gpu agp base 0x%08X\n", MMIO_R(AGP_BASE));
+       DRM_INFO("[radeon_ms] gpu agp location 0x%08X\n",
+                MMIO_R(MC_AGP_LOCATION));
+       DRM_INFO("[radeon_ms] gpu agp location 0x%08X\n",
+                state->mc_agp_location);
+       DRM_INFO("[radeon_ms] bus ready\n");
+       dev_priv->bus_ready = 1;
+       return 0;
+}
+
+void radeon_ms_agp_restore(struct drm_device *dev, struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       MMIO_W(MC_AGP_LOCATION, state->mc_agp_location);
+       MMIO_W(AGP_BASE, state->agp_base);
+       MMIO_W(AGP_BASE_2, state->agp_base_2);
+       MMIO_W(AGP_COMMAND, state->agp_command);
+}
+
+void radeon_ms_agp_save(struct drm_device *dev, struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       state->agp_command = MMIO_R(AGP_COMMAND);
+       state->agp_base = MMIO_R(AGP_BASE);
+       state->agp_base_2 = MMIO_R(AGP_BASE_2);
+       state->mc_agp_location = MMIO_R(MC_AGP_LOCATION);
+}
+
+struct drm_ttm_backend *radeon_ms_pcie_create_ttm(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_pcie_gart *pcie_gart;
+
+       pcie_gart = drm_ctl_calloc(1, sizeof (*pcie_gart), DRM_MEM_TTM);
+       if (pcie_gart == NULL) {
+               return NULL;
+       }
+       memset(pcie_gart, 0, sizeof(struct radeon_pcie_gart));
+       pcie_gart->populated = 0;
+       pcie_gart->pcie = dev_priv->bus;
+       pcie_gart->backend.func = &radeon_pcie_gart_ttm_backend;
+
+       return &pcie_gart->backend;
+}
+
+int radeon_ms_pcie_finish(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_pcie *pcie = dev_priv->bus;
+
+       if (!dev_priv->bus_ready || pcie == NULL) {
+               dev_priv->bus_ready = 0;
+               return 0;
+       }
+       dev_priv->bus_ready = 0;
+       if (pcie->gart_table) {
+               drm_mem_reg_iounmap(dev, &pcie->gart_table_object->mem,
+                                   (void *)pcie->gart_table);
+       }
+       pcie->gart_table = NULL;
+       if (pcie->gart_table_object) {
+               mutex_lock(&dev->struct_mutex);
+               drm_bo_usage_deref_locked(&pcie->gart_table_object);
+               mutex_unlock(&dev->struct_mutex);
+       }
+       dev_priv->bus = NULL;
+       drm_free(pcie, sizeof(*pcie), DRM_MEM_DRIVER);
+       return 0;
+}
+
+int radeon_ms_pcie_init(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+       struct radeon_pcie *pcie;
+       int ret = 0;
+
+       dev_priv->bus_ready = -1;
+       /* allocate and clear device private structure */
+       pcie = drm_alloc(sizeof(struct radeon_pcie), DRM_MEM_DRIVER);
+       if (pcie == NULL) {
+               return -ENOMEM;
+       }
+       memset(pcie, 0, sizeof(struct radeon_pcie));
+       pcie->dev = dev;
+       dev_priv->bus = (void *)pcie;
+       pcie->gart_table_size = (dev_priv->gpu_gart_size / RADEON_PAGE_SIZE) *
+                               4;
+       /* gart table start must be aligned on 16bytes, align it on one page */
+       ret = drm_buffer_object_create(dev,
+                                      pcie->gart_table_size,
+                                      drm_bo_type_kernel,
+                                      DRM_BO_FLAG_READ |
+                                      DRM_BO_FLAG_WRITE |
+                                      DRM_BO_FLAG_MEM_VRAM |
+                                      DRM_BO_FLAG_NO_EVICT,
+                                      DRM_BO_HINT_DONT_FENCE,
+                                      1,
+                                      0,
+                                      &pcie->gart_table_object);
+       if (ret) {
+               return ret;
+       }
+       ret = drm_mem_reg_ioremap(dev, &pcie->gart_table_object->mem,
+                                 (void **) &pcie->gart_table);
+       if (ret) {
+               DRM_ERROR("[radeon_ms] error mapping gart table: %d\n", ret);
+               return ret;
+       }
+       DRM_INFO("[radeon_ms] gart table in vram at 0x%08lX\n",
+                pcie->gart_table_object->offset);
+       memset((void *)pcie->gart_table, 0, pcie->gart_table_size);
+       pcie->page_last = pcie->gart_table_size >> 2;
+       state->pcie_tx_gart_discard_rd_addr_lo =
+               REG_S(PCIE_TX_GART_DISCARD_RD_ADDR_LO,
+                               GART_DISCARD_RD_ADDR_LO,
+                               dev_priv->gpu_gart_start);
+       state->pcie_tx_gart_discard_rd_addr_hi =
+               REG_S(PCIE_TX_GART_DISCARD_RD_ADDR_HI,
+                               GART_DISCARD_RD_ADDR_HI, 0);
+       state->pcie_tx_gart_base =
+               REG_S(PCIE_TX_GART_BASE, GART_BASE,
+                               pcie->gart_table_object->offset);
+       state->pcie_tx_gart_start_lo =
+               REG_S(PCIE_TX_GART_START_LO, GART_START_LO,
+                               dev_priv->gpu_gart_start);
+       state->pcie_tx_gart_start_hi =
+               REG_S(PCIE_TX_GART_START_HI, GART_START_HI, 0);
+       state->pcie_tx_gart_end_lo =
+               REG_S(PCIE_TX_GART_END_LO, GART_END_LO, dev_priv->gpu_gart_end);
+       state->pcie_tx_gart_end_hi =
+               REG_S(PCIE_TX_GART_END_HI, GART_END_HI, 0);
+       /* FIXME: why this ? */
+       state->aic_ctrl = 0;
+       state->agp_base = 0; 
+       state->agp_base_2 = 0; 
+       state->bus_cntl = MMIO_R(BUS_CNTL);
+       state->mc_agp_location = REG_S(MC_AGP_LOCATION, MC_AGP_START, 0xffc0) |
+                                REG_S(MC_AGP_LOCATION, MC_AGP_TOP, 0xffff);
+       state->pcie_tx_gart_cntl =
+               PCIE_TX_GART_CNTL__GART_EN |
+               REG_S(PCIE_TX_GART_CNTL, GART_UNMAPPED_ACCESS,
+                               GART_UNMAPPED_ACCESS__DISCARD) |
+               REG_S(PCIE_TX_GART_CNTL, GART_MODE, GART_MODE__CACHE_32x128) |
+               REG_S(PCIE_TX_GART_CNTL, GART_RDREQPATH_SEL,
+                               GART_RDREQPATH_SEL__HDP);
+       DRM_INFO("[radeon_ms] gpu gart start 0x%08X\n",
+                PCIE_R(PCIE_TX_GART_START_LO));
+       DRM_INFO("[radeon_ms] gpu gart end   0x%08X\n",
+                PCIE_R(PCIE_TX_GART_END_LO));
+       DRM_INFO("[radeon_ms] bus ready\n");
+       dev_priv->bus_ready = 1;
+       return 0;
+}
+
+void radeon_ms_pcie_restore(struct drm_device *dev, struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       /* disable gart before programing other registers */
+       radeon_ms_agp_restore(dev, state);
+       PCIE_W(PCIE_TX_GART_CNTL, 0);
+       PCIE_W(PCIE_TX_GART_BASE, state->pcie_tx_gart_base);
+       PCIE_W(PCIE_TX_GART_BASE, state->pcie_tx_gart_base);
+       PCIE_W(PCIE_TX_GART_DISCARD_RD_ADDR_HI,
+              state->pcie_tx_gart_discard_rd_addr_hi);
+       PCIE_W(PCIE_TX_GART_DISCARD_RD_ADDR_LO,
+              state->pcie_tx_gart_discard_rd_addr_lo);
+       PCIE_W(PCIE_TX_GART_START_HI, state->pcie_tx_gart_start_hi);
+       PCIE_W(PCIE_TX_GART_START_LO, state->pcie_tx_gart_start_lo);
+       PCIE_W(PCIE_TX_GART_END_HI, state->pcie_tx_gart_end_hi);
+       PCIE_W(PCIE_TX_GART_END_LO, state->pcie_tx_gart_end_lo);
+       PCIE_W(PCIE_TX_GART_CNTL, state->pcie_tx_gart_cntl);
+}
+
+void radeon_ms_pcie_save(struct drm_device *dev, struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       radeon_ms_agp_save(dev, state);
+       state->pcie_tx_gart_base = PCIE_R(PCIE_TX_GART_BASE);
+       state->pcie_tx_gart_base = PCIE_R(PCIE_TX_GART_BASE);
+       state->pcie_tx_gart_discard_rd_addr_hi =
+               PCIE_R(PCIE_TX_GART_DISCARD_RD_ADDR_HI);
+       state->pcie_tx_gart_discard_rd_addr_lo =
+               PCIE_R(PCIE_TX_GART_DISCARD_RD_ADDR_LO);
+       state->pcie_tx_gart_start_hi = PCIE_R(PCIE_TX_GART_START_HI);
+       state->pcie_tx_gart_start_lo = PCIE_R(PCIE_TX_GART_START_LO);
+       state->pcie_tx_gart_end_hi = PCIE_R(PCIE_TX_GART_END_HI);
+       state->pcie_tx_gart_end_lo = PCIE_R(PCIE_TX_GART_END_LO);
+       state->pcie_tx_gart_cntl = PCIE_R(PCIE_TX_GART_CNTL);
+}
diff --git a/shared-core/radeon_ms_combios.c b/shared-core/radeon_ms_combios.c
new file mode 100644 (file)
index 0000000..65609af
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ */
+/*
+ * Authors:
+ *    Jérôme Glisse <glisse@freedesktop.org>
+ */
+#include "radeon_ms.h"
+
+extern struct radeon_ms_output radeon_ms_dac1;
+extern struct radeon_ms_output radeon_ms_dac2;
+extern const struct drm_output_funcs radeon_ms_output_funcs;
+
+static struct combios_connector_chip_info *
+radeon_ms_combios_get_connector_chip_info(struct drm_device *dev, int chip_num)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_ms_rom *rom = &dev_priv->rom;
+       struct combios_header *header;
+       struct combios_connector_table *connector_table;
+       struct combios_connector_chip_info *connector_chip_info;
+       uint32_t offset;
+       int numof_chips, i;
+
+       if (rom->type != ROM_COMBIOS || rom->rom_image == NULL) {
+               return NULL;
+       }
+       header = rom->rom.combios_header;
+       offset = header->usPointerToExtendedInitTable2;
+       if ((offset + sizeof(struct combios_connector_table)) > rom->rom_size) {
+               DRM_INFO("[radeon_ms] wrong COMBIOS connector offset\n");
+               return NULL;
+       }
+       if (!offset) {
+               return NULL;
+       }
+       connector_table = (struct combios_connector_table *)
+                         &rom->rom_image[offset];
+       numof_chips = (connector_table->ucConnectorHeader &
+                      BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__MASK) >>
+                     BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__SHIFT;
+       DRM_INFO("[radeon_ms] COMBIOS number of chip: %d (table rev: %d)\n",
+                numof_chips,
+                (connector_table->ucConnectorHeader &
+                 BIOS_CONNECTOR_HEADER__TABLE_REVISION__MASK) >>
+                BIOS_CONNECTOR_HEADER__TABLE_REVISION__SHIFT);
+       for (i = 0; i < numof_chips; i++) {
+               int chip;
+
+               connector_chip_info = &connector_table->sChipConnectorInfo[i];
+               chip = (connector_chip_info->ucChipHeader &
+                       BIOS_CHIPINFO_HEADER__CHIP_NUMBER__MASK) >>
+                      BIOS_CHIPINFO_HEADER__CHIP_NUMBER__SHIFT;
+               DRM_INFO("[radeon_ms] COMBIOS chip: %d (asked for: %d)\n",
+                        chip, chip_num);
+               if (chip == chip_num) {
+                       return connector_chip_info;
+               }
+       }
+       return NULL;
+}
+
+static int radeon_combios_get_connector_infos(struct drm_device *dev,
+                                             int connector_info, 
+                                             int *connector_type, 
+                                             int *ddc_line,
+                                             int *tmds_type,
+                                             int *dac_type)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       *connector_type = (connector_info & BIOS_CONNECTOR_INFO__TYPE__MASK) >>
+                         BIOS_CONNECTOR_INFO__TYPE__SHIFT;
+       *ddc_line = (connector_info & BIOS_CONNECTOR_INFO__DDC_LINE__MASK) >>
+                   BIOS_CONNECTOR_INFO__DDC_LINE__SHIFT;
+       *tmds_type = (connector_info & BIOS_CONNECTOR_INFO__TMDS_TYPE__MASK) >>
+                    BIOS_CONNECTOR_INFO__TMDS_TYPE__SHIFT;
+       *dac_type = (connector_info & BIOS_CONNECTOR_INFO__DAC_TYPE__MASK) >>
+                   BIOS_CONNECTOR_INFO__DAC_TYPE__SHIFT;
+
+       /* most XPRESS chips seem to specify DDC_CRT2 for their 
+        * VGA DDC port, however DDC never seems to work on that
+        * port.  Some have reported success on DDC_MONID, so 
+        * lets see what happens with that.
+        */
+       if (dev_priv->family == CHIP_RS400 &&
+           *connector_type == BIOS_CONNECTOR_TYPE__CRT &&
+           *ddc_line == BIOS_DDC_LINE__CRT2) {
+               *ddc_line = BIOS_DDC_LINE__MONID01;
+       }
+       /* XPRESS desktop chips seem to have a proprietary
+        * connector listed for DVI-D, try and do the right
+        * thing here.
+        */
+       if (dev_priv->family == CHIP_RS400 &&
+           *connector_type == BIOS_CONNECTOR_TYPE__PROPRIETARY) {
+               DRM_INFO("[radeon_ms] COMBIOS Proprietary connector "
+                        "found, assuming DVI-D\n");
+               *dac_type = 2;
+               *tmds_type = BIOS_TMDS_TYPE__EXTERNAL;
+               *connector_type = BIOS_CONNECTOR_TYPE__DVI_D;
+       }
+       return 0;
+}
+
+static int radeon_ms_combios_connector_add(struct drm_device *dev,
+                                          int connector_number,
+                                          int connector_type,
+                                          uint32_t i2c_reg)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_ms_connector *connector = NULL;
+       struct drm_output *output = NULL;
+
+       connector = drm_alloc(sizeof(struct radeon_ms_connector),
+                             DRM_MEM_DRIVER);
+       if (connector == NULL) {
+               radeon_ms_connectors_destroy(dev);
+               return -ENOMEM;
+       }
+       memset(connector, 0, sizeof(struct radeon_ms_connector));
+       connector->monitor_type = MT_NONE;
+       connector->type = connector_type;
+       connector->i2c_reg = i2c_reg;
+
+       switch (connector->type) {
+       case CONNECTOR_VGA:
+               sprintf(connector->name, "VGA");
+               break;
+       case CONNECTOR_DVI_I:
+               sprintf(connector->name, "DVI-I");
+               break;
+       case CONNECTOR_DVI_D:
+               sprintf(connector->name, "DVI-D");
+               break;
+       default:
+               sprintf(connector->name, "UNKNOWN-CONNECTOR");
+               break;
+       }
+
+       if (i2c_reg) {
+               connector->i2c = radeon_ms_i2c_create(dev,
+                                                     connector->i2c_reg,
+                                                     connector->name);
+               if (connector->i2c == NULL) {
+                       radeon_ms_connectors_destroy(dev);
+                       return -ENOMEM;
+               }
+       } else {
+               connector->i2c = NULL;
+       }
+
+       output = drm_output_create(dev, &radeon_ms_output_funcs,
+                                  connector->type);
+       if (output == NULL) {
+               radeon_ms_connectors_destroy(dev);
+               return -EINVAL;
+       }
+       connector->output = output;
+       output->driver_private = connector;
+       output->possible_crtcs = 0x3;
+       dev_priv->connectors[connector_number] = connector;
+       return 0;
+}
+
+int radeon_ms_combios_get_properties(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_ms_rom *rom = &dev_priv->rom;
+       struct combios_pll_block *pll_block;
+       struct combios_header *header;
+       uint32_t offset;
+
+       if (rom->type != ROM_COMBIOS || rom->rom_image == NULL) {
+               return 0;
+       }
+       header = rom->rom.combios_header;
+       offset = header->usPointerToPllInfoBlock;
+       if ((offset + sizeof(struct combios_pll_block)) > rom->rom_size) {
+               DRM_INFO("[radeon_ms] wrong COMBIOS pll block offset\n");
+               return 0;
+       }
+       if (!offset) {
+               return 0;
+       }
+       pll_block = (struct combios_pll_block *)&rom->rom_image[offset];
+       dev_priv->properties.pll_reference_freq = pll_block->usDotClockRefFreq;
+       dev_priv->properties.pll_reference_div = pll_block->usDotClockRefDiv;
+       dev_priv->properties.pll_min_pll_freq = pll_block->ulDotClockMinFreq;
+       dev_priv->properties.pll_max_pll_freq = pll_block->ulDotClockMaxFreq;
+       dev_priv->properties.pll_reference_freq *= 10;
+       dev_priv->properties.pll_min_pll_freq *= 10;
+       dev_priv->properties.pll_max_pll_freq *= 10;
+       DRM_INFO("[radeon_ms] COMBIOS pll reference frequency : %d\n",
+                dev_priv->properties.pll_reference_freq);
+       DRM_INFO("[radeon_ms] COMBIOS pll reference divider   : %d\n",
+                dev_priv->properties.pll_reference_div);
+       DRM_INFO("[radeon_ms] COMBIOS pll minimum frequency   : %d\n",
+                dev_priv->properties.pll_min_pll_freq);
+       DRM_INFO("[radeon_ms] COMBIOS pll maximum frequency   : %d\n",
+                dev_priv->properties.pll_max_pll_freq);
+       return 1;
+}
+
+int radeon_ms_connectors_from_combios(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct combios_connector_chip_info *connector_chip_info;
+       int connector_type, ddc_line, tmds_type, dac_type;
+       int dac1, dac2, tmdsint, tmdsext;
+       int numof_connector, i, c = 0, added, j;
+       uint32_t i2c_reg;
+       int ret;
+
+       dac1 = dac2 = tmdsint = tmdsext = -1;
+       connector_chip_info = radeon_ms_combios_get_connector_chip_info(dev, 1);
+       if (connector_chip_info == NULL) {
+               return -1;
+       }
+       numof_connector = (connector_chip_info->ucChipHeader &
+                          BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__MASK) >>
+                         BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__SHIFT;
+       DRM_INFO("[radeon_ms] COMBIOS number of connector: %d\n",
+                numof_connector);
+       for (i = 0; i < numof_connector; i++) {
+               int connector_info = connector_chip_info->sConnectorInfo[i];
+
+               ret = radeon_combios_get_connector_infos(dev,
+                                                        connector_info, 
+                                                        &connector_type, 
+                                                        &ddc_line,
+                                                        &tmds_type,
+                                                        &dac_type);
+
+               switch (ddc_line) {
+               case BIOS_DDC_LINE__MONID01:
+                       i2c_reg = GPIO_MONID;
+                       break;
+               case BIOS_DDC_LINE__DVI:
+                       i2c_reg =  GPIO_DVI_DDC;
+                       break;
+               case BIOS_DDC_LINE__VGA:
+                       i2c_reg = GPIO_DDC1;
+                       break;
+               case BIOS_DDC_LINE__CRT2:
+                       i2c_reg = GPIO_CRT2_DDC;
+                       break;
+               case BIOS_DDC_LINE__GPIOPAD:
+                       i2c_reg = VIPPAD_EN;
+                       break;
+               case BIOS_DDC_LINE__ZV_LCDPAD:
+                       i2c_reg = VIPPAD1_EN;
+                       break;
+               default:
+                       i2c_reg = 0;
+                       break;
+               }
+               added = 0;
+               switch (connector_type) {
+               case BIOS_CONNECTOR_TYPE__CRT:
+                       ret = radeon_ms_combios_connector_add(dev, c,
+                                                             CONNECTOR_VGA,
+                                                             i2c_reg);
+                       if (ret) {
+                               return ret;
+                       }
+                       added = 1;
+                       break;
+               case BIOS_CONNECTOR_TYPE__DVI_I:
+                       ret = radeon_ms_combios_connector_add(dev, c,
+                                                             CONNECTOR_DVI_I,
+                                                             i2c_reg);
+                       if (ret) {
+                               return ret;
+                       }
+                       added = 1;
+                       break;
+               case BIOS_CONNECTOR_TYPE__DVI_D:
+                       ret = radeon_ms_combios_connector_add(dev, c,
+                                                             CONNECTOR_DVI_D,
+                                                             i2c_reg);
+                       if (ret) {
+                               return ret;
+                       }
+                       added = 1;
+                       break;
+               default:
+                       break;
+               }
+               if (added) {
+                       j = 0;
+                       /* find to which output this connector is associated 
+                        * by following same algo as in:
+                        * radeon_ms_outputs_from_combios*/
+                       switch (dac_type) {
+                       case BIOS_DAC_TYPE__CRT:
+                               if (dac1 == -1) {
+                                       dac1 = c;
+                               }
+                               dev_priv->connectors[c]->outputs[j++] = dac1;
+                               break;
+                       case BIOS_DAC_TYPE__NON_CRT:
+                               if (dac2 == -1) {
+                                       dac2 = c;
+                               }
+                               dev_priv->connectors[c]->outputs[j++] = dac2;
+                               break;
+                       }
+#if 0
+                       switch (tmds_type) {
+                       case BIOS_TMDS_TYPE__INTERNAL:
+                               if (tmdsint == -1) {
+                                       tmdsint = c;
+                               }
+                               dev_priv->connectors[c]->outputs[j++] = tmdsint;
+                               break;
+                       case BIOS_TMDS_TYPE__EXTERNAL:
+                               if (tmdsext == -1) {
+                                       tmdsext = c;
+                               }
+                               dev_priv->connectors[c]->outputs[j++] = tmdsext;
+                               break;
+                       }
+#endif
+                       c++;
+               }
+       }
+       return c;
+}
+
+int radeon_ms_outputs_from_combios(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct combios_connector_chip_info *connector_chip_info;
+       int connector_type, ddc_line, tmds_type, dac_type;
+       int numof_connector, i, dac1_present, dac2_present, c = 0;
+       int ret;
+
+       dac1_present = dac2_present = 0;
+       connector_chip_info = radeon_ms_combios_get_connector_chip_info(dev, 1);
+       if (connector_chip_info == NULL) {
+               return -1;
+       }
+       numof_connector = (connector_chip_info->ucChipHeader &
+                          BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__MASK) >>
+                         BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__SHIFT;
+       DRM_INFO("[radeon_ms] COMBIOS number of connector: %d\n",
+                numof_connector);
+       for (i = 0; i < numof_connector; i++) {
+               int connector_info = connector_chip_info->sConnectorInfo[i];
+
+               ret = radeon_combios_get_connector_infos(dev,
+                                                        connector_info, 
+                                                        &connector_type, 
+                                                        &ddc_line,
+                                                        &tmds_type,
+                                                        &dac_type);
+
+               if (!dac1_present && dac_type == BIOS_DAC_TYPE__CRT) {
+                       dev_priv->outputs[c] =
+                               drm_alloc(sizeof(struct radeon_ms_output),
+                                         DRM_MEM_DRIVER);
+                       if (dev_priv->outputs[c] == NULL) {
+                               radeon_ms_outputs_destroy(dev);
+                               return -ENOMEM;
+                       }
+                       memcpy(dev_priv->outputs[c], &radeon_ms_dac1,
+                              sizeof(struct radeon_ms_output));
+                       dev_priv->outputs[c]->dev = dev;
+                       dev_priv->outputs[c]->initialize(dev_priv->outputs[c]);
+                       dac1_present = 1;
+                       c++;
+               }
+               if (!dac2_present && dac_type == BIOS_DAC_TYPE__NON_CRT) {
+                       dev_priv->outputs[c] =
+                               drm_alloc(sizeof(struct radeon_ms_output),
+                                         DRM_MEM_DRIVER);
+                       if (dev_priv->outputs[c] == NULL) {
+                               radeon_ms_outputs_destroy(dev);
+                               return -ENOMEM;
+                       }
+                       memcpy(dev_priv->outputs[c], &radeon_ms_dac2,
+                              sizeof(struct radeon_ms_output));
+                       dev_priv->outputs[c]->dev = dev;
+                       dev_priv->outputs[c]->initialize(dev_priv->outputs[c]);
+                       dac1_present = 1;
+                       c++;
+               }
+       }
+       return c;
+}
diff --git a/shared-core/radeon_ms_combios.h b/shared-core/radeon_ms_combios.h
new file mode 100644 (file)
index 0000000..fbceadf
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * Copyright 2006-2007 Advanced Micro Devices, Inc.
+ * Copyright 2007 Jérôme Glisse
+ *
+ * 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
+ * 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 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ */
+/*
+ * Authors:
+ *    Jérôme Glisse <glisse@freedesktop.org>
+ */
+#ifndef __RADEON_MS_COMBIOS_H__
+#define __RADEON_MS_COMBIOS_H__
+
+#pragma pack(1)
+
+#define ROM_HEADER                      0x48
+
+struct combios_header
+{
+    uint8_t  ucTypeDefinition;
+    uint8_t  ucExtFunctionCode;
+    uint8_t  ucOemID1;
+    uint8_t  ucOemID2;
+    uint8_t  ucBiosMajorRev;
+    uint8_t  ucBiosMinorRev;
+    uint16_t usStructureSize;
+    uint16_t usPointerToSmi;
+    uint16_t usPointerToPmid;
+    uint16_t usPointerToInitTable;
+    uint16_t usPointerToCrcChecksumBlock;
+    uint16_t usPointerToConfigFilename;
+    uint16_t usPointerToLogonMessage;
+    uint16_t usPointerToMiscInfo;
+    uint16_t usPciBusDevInitCode;
+    uint16_t usBiosRuntimeSegmentAddress;
+    uint16_t usIoBaseAddress;
+    uint16_t usSubsystemVendorID;
+    uint16_t usSubsystemID;
+    uint16_t usPostVendorID;
+    uint16_t usInt10Offset;
+    uint16_t usInt10Segment;
+    uint16_t usMonitorInfo;
+    uint16_t usPointerToConfigBlock;
+    uint16_t usPointerToDacDelayInfo;
+    uint16_t usPointerToCapDataStruct;
+    uint16_t usPointerToInternalCrtTables;
+    uint16_t usPointerToPllInfoBlock;
+    uint16_t usPointerToTVInfoTable;
+    uint16_t usPointerToDFPInfoTable;
+    uint16_t usPointerToHWConfigTable;
+    uint16_t usPointerToMMConfigTable;
+    uint32_t ulTVStdPatchTableSignature;
+    uint16_t usPointerToTVStdPatchTable;
+    uint16_t usPointerToPanelInfoTable;
+    uint16_t usPointerToAsicInfoTable;
+    uint16_t usPointerToAuroraInfoTable;
+    uint16_t usPointerToPllInitTable;
+    uint16_t usPointerToMemoryConfigTable;
+    uint16_t usPointerToSaveMaskTable;
+    uint16_t usPointerHardCodedEdid;
+    uint16_t usPointerToExtendedInitTable1;
+    uint16_t usPointerToExtendedInitTable2;
+    uint16_t usPointerToDynamicClkTable;
+    uint16_t usPointerToReservedMemoryTable;
+    uint16_t usPointerToBridgetInitTable;
+    uint16_t usPointerToExtTMDSInitTable;
+    uint16_t usPointerToMemClkInfoTable;
+    uint16_t usPointerToExtDACTable;
+    uint16_t usPointerToMiscInfoTable;
+};
+
+struct combios_pll_block
+{
+    /* Usually 6 */
+    uint8_t  ucPLLBiosVersion;
+    /* Size in bytes */
+    uint8_t  ucStructureSize;
+    /* Dot clock entry used for accelerated modes */
+    uint8_t  ucDotClockEntry;
+    /* Dot clock entry used for extended VGA modes */
+    uint8_t  ucDotClockEntryVga;
+    /* Offset into internal clock table used for by VGA parameter table */
+    uint16_t usPointerToInternalClock;
+    /* Offset into actual programmed frequency table at POST */
+    uint16_t usPointerToFreqTable;
+    /* XCLK setting, (memory clock in 10 KHz units) */
+    uint16_t usXclkSetting;
+    /* MCLK setting, (engine clock in 10 KHz units) */
+    uint16_t usMclkSetting;
+    /* Number of PLL information block to follow, currently value is 3 */
+    uint8_t  ucPllInfoBlockNumber;
+    /* Size of each PLL information block */
+    uint8_t  ucPllInfoBlockSize;
+    /* Reference frequency of the dot clock */
+    uint16_t usDotClockRefFreq;
+    /* Reference Divider of the dot clock */
+    uint16_t usDotClockRefDiv;
+    /* Min Frequency supported before post divider for the dot clock */
+    uint32_t ulDotClockMinFreq;
+    /* Max Frequency can be supported for the dot clock */
+    uint32_t ulDotClockMaxFreq;
+    /* Reference frequency of the MCLK, engine clock */
+    uint16_t usMclkRefFreq;
+    /* Reference Divider of the MCLK, engine clock */
+    uint16_t usMclkRefDiv;
+    /* Min Frequency supported before post divider for MCLK, engine clock */
+    uint32_t ulMclkMinFreq;
+    /* Max Frequency can be supported for the MCLK, engine clock */
+    uint32_t ulMclkMaxFreq;
+    /* Reference frequency of the XCLK, memory clock */
+    uint16_t usXclkRefFreq;
+    /* Reference Divider of the XCLK, memory clock */
+    uint16_t usXclkRefDiv;
+    /* Min Frequency supported before post divider for XCLK, memory clock */
+    uint32_t ulXclkMinFreq;
+    /* Max Frequency can be supported for the XCLK, memory clock */
+    uint32_t ulXclkMaxFreq;
+
+    /*this is the PLL Information Table Extended structure version 10 */
+    uint8_t  ucNumberOfExtendedPllBlocks;
+    uint8_t  ucSizePLLDefinition;
+    uint16_t ulCrystalFrequencyPixelClock_pll;
+    uint32_t ulMinInputPixelClockPLLFrequency;
+    uint32_t ulMaxInputPixelClockPLLFrequency;
+    uint32_t ulMinOutputPixelClockPLLFrequency;
+    uint32_t ulMaxOutputPixelClockPLLFrequency;
+
+    /*version 11 */
+    uint16_t ulCrystalFrequencyEngineClock_pll;
+    uint32_t ulMinInputFrequencyEngineClock_pll;
+    uint32_t ulMaxInputFrequencyEngineClock_pll;
+    uint32_t ulMinOutputFrequencyEngineClock_pll;
+    uint32_t ulMaxOutputFrequencyEngineClock_pll;
+    uint16_t ulCrystalFrequencyMemoryClock_pll;
+    uint32_t ulMinInputFrequencyMemoryClock_pll;
+    uint32_t ulMaxInputFrequencyMemoryClock_pll;
+    uint32_t ulMinOutputFrequencyMemoryClock_pll;
+    uint32_t ulMaxOutputFrequencyMemoryClock_pll;
+    uint32_t ulMaximumDACOutputFrequency;
+};
+
+#define MAX_NO_OF_LCD_RES_TIMING                25
+
+struct panel_information_table
+{
+    uint8_t  ucPanelIdentification;
+    uint8_t  ucPanelIDString[24];
+    uint16_t usHorizontalSize;
+    uint16_t usVerticalSize;
+    uint16_t usFlatPanelType;
+    uint8_t  ucRedBitsPerPrimary;
+    uint8_t  ucGreenBitsPerPrimary;
+    uint8_t  ucBlueBitsPerPrimary;
+    uint8_t  ucReservedBitsPerPrimary;
+    uint8_t  ucPanelCaps;
+    uint8_t  ucPowerSequenceDelayStepsInMS;
+    uint8_t  ucSupportedRefreshRateExtended;
+    uint16_t usExtendedPanelInfoTable;
+    uint16_t usPtrToHalfFrameBufferInformationTable;
+    uint16_t usVccOntoBlOn;
+    uint16_t usOffDelay;
+    uint16_t usRefDiv;
+    uint8_t  ucPostDiv;
+    uint16_t usFeedBackDiv;
+    uint8_t  ucSpreadSpectrumType;
+    uint16_t usSpreadSpectrumPercentage;
+    uint8_t  ucBackLightLevel;
+    uint8_t  ucBiasLevel;
+    uint8_t  ucPowerSequenceDelay;
+    uint32_t ulPanelData;
+    uint8_t  ucPanelRefreshRateData;
+    uint16_t usSupportedRefreshRate;
+    uint16_t usModeTableOffset[MAX_NO_OF_LCD_RES_TIMING];
+};
+
+struct extended_panel_info_table
+{
+    uint8_t  ucExtendedPanelInfoTableVer;
+    uint8_t  ucSSDelay;
+    uint8_t  ucSSStepSizeIndex;
+};
+
+struct lcd_mode_table_center
+{
+    uint16_t usHorizontalRes;
+    uint16_t usVerticalRes;
+    uint8_t  ucModeType;
+    uint16_t usOffset2ExpParamTable;
+    uint16_t usOffset2TvParamTable;
+    uint16_t usPixelClock;
+    uint16_t usPixelClockAdjustment;
+    uint16_t usFpPos;
+    uint8_t  ucReserved;
+    uint8_t  ucMiscBits;
+    uint16_t usCrtcHTotal;
+    uint16_t usCrtcHDisp;
+    uint16_t usCrtcHSyncStrt;
+    uint8_t  ucCrtcHSyncWid;
+    uint16_t usCrtcVTotal;
+    uint16_t usCrtcVDisp;
+    uint16_t usCrtcVSyncStrt;
+    uint8_t  ucOvrWidTop;
+};
+
+struct lcd_mode_table_exp
+{
+    uint16_t usPixelClock;
+    uint16_t usPixelClockAdjustment;
+    uint16_t usFpPos;
+    uint8_t  ucReserved;
+    uint8_t  ucMiscBits;
+    uint16_t usCrtcHTotal;
+    uint16_t usCrtcHDisp;
+    uint16_t usCrtcHSyncStrt;
+    uint8_t  ucCrtcHSyncWid;
+    uint16_t usCrtcVTotal;
+    uint16_t usCrtcVDisp;
+    uint16_t usCrtcVSyncStrt;
+    uint8_t  ucOvrWidTop;
+    uint16_t usHorizontalBlendRatio;
+    uint32_t ulVgaVertStretching;
+    uint16_t usCopVertStretching;
+    uint16_t usVgaExtVertStretching;
+};
+
+struct tmds_pll_cntl_block
+{
+    uint16_t usClockUpperRange;
+    uint32_t ulPllSetting;
+};
+
+#define MAX_PLL_CNTL_ENTRIES                    8
+
+struct combios_dfp_info_table
+{
+    uint8_t                     ucDFPInfoTableRev;
+    uint8_t                     ucDFPInfoTableSize;
+    uint16_t                    usOffsetDetailedTimingTable;
+    uint8_t                     ucReserved;
+    uint8_t                     ucNumberOfClockRanges;
+    uint16_t                    usMaxPixelClock;
+    uint32_t                    ulInitValueTmdsPllCntl;
+    uint32_t                    ulFinalValueTmdsPllCntl;
+    struct tmds_pll_cntl_block  sTmdsPllCntlBlock[MAX_PLL_CNTL_ENTRIES];
+};
+
+struct combios_exttmds_table_header
+{
+    uint8_t  ucTableRev;
+    uint16_t usTableSize;
+    uint8_t  ucNoBlocks;
+};
+
+struct combios_exttmds_block_header
+{
+    uint16_t usMaxFreq;
+    uint8_t  ucI2CSlaveAddr;
+    uint8_t  ucI2CLine;
+    uint8_t  ucConnectorId;
+    uint8_t  ucFlags;
+};
+
+/* Connector table - applicable from Piglet and later ASICs
+    byte 0     (embedded revision)
+        [7:4]    = number of chips (valid number 1 - 15)
+        [3:0]    = revision number of table (valid number 1 - 15)
+
+    byte 1 (Chip info)
+        [7:4]    = chip number, max. 15 (valid number 1 - 15)
+        [3:0]    = number of connectors for that chip, (valid number 1 - 15)
+                   (number of connectors = number of 'Connector info' entries
+                    for that chip)
+
+    byte 2,3 (Connector info)
+        [15:12]    - connector type
+            = 0     - no connector
+            = 1     - proprietary
+            = 2     - CRT
+            = 3     - DVI-I
+            = 4      - DVI-D
+            = 5-15    - reserved for future expansion
+        [11:8]    - DDC line pair used for that connector
+            = 0     - no DDC
+            = 1     - MONID 0/1
+            = 2     - DVI_DDC
+            = 3     - VGA_DDC
+            = 4     - CRT2_DDC
+            = 5-15    - reserved for future expansion
+        [5] - bit indicating presence of multiplexer for TV,CRT2
+        [7:6]    - reserved for future expansion
+        [4]    - TMDS type
+            = 0     - internal TMDS
+            = 1      - external TMDS
+        [3:1]    - reserved for future expansion
+        [0]    - DAC associated with that connector
+            = 0    - CRT DAC
+            = 1    - non-CRT DAC (e.g. TV DAC, external DAC ..)
+
+    byte 4,5,6...     - byte 4,5 can be another "Connector info" word
+                      describing another connector
+                     - or byte 5 is a "Chip info" byte for anther chip,
+                      then start with byte 5,6 to describe connectors
+                      for that chip
+                    - or byte 5 = 0 if all connectors for all chips on
+                      board have been described, no more connector left
+                      to describe.
+*/
+#define BIOS_CONNECTOR_INFO__TYPE__MASK                   0xF000
+#define BIOS_CONNECTOR_INFO__TYPE__SHIFT                  0x0000000C
+#define BIOS_CONNECTOR_TYPE__NONE                         0x00000000
+#define BIOS_CONNECTOR_TYPE__PROPRIETARY                  0x00000001
+#define BIOS_CONNECTOR_TYPE__CRT                          0x00000002
+#define BIOS_CONNECTOR_TYPE__DVI_I                        0x00000003
+#define BIOS_CONNECTOR_TYPE__DVI_D                        0x00000004
+
+#define BIOS_CONNECTOR_INFO__DDC_LINE__MASK               0x0F00
+#define BIOS_CONNECTOR_INFO__DDC_LINE__SHIFT              0x00000008
+#define BIOS_DDC_LINE__NONE                               0x00000000
+#define BIOS_DDC_LINE__MONID01                            0x00000001
+#define BIOS_DDC_LINE__DVI                                0x00000002
+#define BIOS_DDC_LINE__VGA                                0x00000003
+#define BIOS_DDC_LINE__CRT2                               0x00000004
+#define BIOS_DDC_LINE__GPIOPAD                            0x00000005
+#define BIOS_DDC_LINE__ZV_LCDPAD                          0x00000006
+
+#define BIOS_CONNECTOR_INFO__TMDS_TYPE__MASK              0x0010
+#define BIOS_CONNECTOR_INFO__TMDS_TYPE__SHIFT             0x00000004
+#define BIOS_TMDS_TYPE__INTERNAL                          0x00000000
+#define BIOS_TMDS_TYPE__EXTERNAL                          0x00000001
+
+#define BIOS_CONNECTOR_INFO__DAC_TYPE__MASK               0x0001
+#define BIOS_CONNECTOR_INFO__DAC_TYPE__SHIFT              0x00000000
+#define BIOS_DAC_TYPE__CRT                                0x00000000
+#define BIOS_DAC_TYPE__NON_CRT                            0x00000001
+
+#define BIOS_CONNECTOR_INFO__MUX_MASK                     0x00000020
+#define BIOS_CONNECTOR_INFO__MUX_SHIFT                    0x00000005
+
+#define BIOS_CHIPINFO_HEADER__CHIP_NUMBER__MASK           0xF0
+#define BIOS_CHIPINFO_HEADER__CHIP_NUMBER__SHIFT          0x00000004
+
+#define BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__MASK  0x0F
+#define BIOS_CHIPINFO_HEADER__NUMBER_OF_CONNECTORS__SHIFT 0x00000000
+
+#define BIOS_CHIPINFO__MAX_NUMBER_OF_CONNECTORS           0x00000010
+
+struct combios_connector_chip_info
+{
+    uint8_t  ucChipHeader;
+    uint16_t sConnectorInfo[BIOS_CHIPINFO__MAX_NUMBER_OF_CONNECTORS];
+};
+
+#define BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__MASK      0xF0
+#define BIOS_CONNECTOR_HEADER__NUMBER_OF_CHIPS__SHIFT     0x00000004
+
+#define BIOS_CONNECTOR_HEADER__TABLE_REVISION__MASK       0x0F
+#define BIOS_CONNECTOR_HEADER__TABLE_REVISION__SHIFT      0x00000000
+
+struct combios_connector_table
+{
+    uint8_t                            ucConnectorHeader;
+    struct combios_connector_chip_info sChipConnectorInfo[0x10];
+};
+
+#pragma pack()
+
+int combios_parse(unsigned char *rom, struct combios_header *header);
+
+#endif
diff --git a/shared-core/radeon_ms_cp.c b/shared-core/radeon_ms_cp.c
new file mode 100644 (file)
index 0000000..c01769b
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * Copyright 2007 Dave Airlie
+ * Copyright 2007 Alex Deucher
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ */
+/*
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#include "radeon_ms.h"
+
+static int radeon_ms_test_ring_buffer(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       int i, ret;
+       uint32_t cmd[4];
+
+       MMIO_W(SCRATCH_REG4, 0);
+       cmd[0] = CP_PACKET0(SCRATCH_REG4, 0);
+       cmd[1] = 0xdeadbeef;
+       cmd[2] = CP_PACKET0(WAIT_UNTIL, 0);
+       cmd[3] = WAIT_UNTIL__WAIT_2D_IDLECLEAN |
+               WAIT_UNTIL__WAIT_HOST_IDLECLEAN;
+       DRM_MEMORYBARRIER();
+       ret = radeon_ms_ring_emit(dev, cmd, 4);
+       if (ret) {
+               return 0;
+       }
+       DRM_UDELAY(100);
+
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               if (MMIO_R(SCRATCH_REG4) == 0xdeadbeef) {
+                       DRM_INFO("[radeon_ms] cp test succeeded in %d usecs\n",
+                                i);
+                       return 1;
+               }
+               DRM_UDELAY(1);
+       }
+       DRM_INFO("[radeon_ms] cp test failed\n");
+       return 0;
+}
+
+static int radeon_ms_test_write_back(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       uint32_t tmp;
+
+       if (dev_priv->ring_buffer_object == NULL ||
+           dev_priv->ring_buffer == NULL)
+           return 0;
+       dev_priv->write_back_area[0] = 0x0;
+       MMIO_W(SCRATCH_REG0, 0xdeadbeef);
+       for (tmp = 0; tmp < dev_priv->usec_timeout; tmp++) {
+               if (dev_priv->write_back_area[0] == 0xdeadbeef)
+                       break;
+               DRM_UDELAY(1);
+       }
+       if (tmp < dev_priv->usec_timeout) {
+               DRM_INFO("[radeon_ms] writeback test succeeded in %d usecs\n",
+                        tmp);
+               return 1;
+       }
+       MMIO_W(SCRATCH_UMSK, 0x0);
+       DRM_INFO("[radeon_ms] writeback test failed\n");
+       return 0;
+}
+
+static __inline__ void radeon_ms_load_mc(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       int i;
+
+       MMIO_W(CP_ME_RAM_ADDR, 0);
+       for (i = 0; i < 256; i++) {
+               MMIO_W(CP_ME_RAM_DATAH, dev_priv->microcode[(i * 2) + 1]);
+               MMIO_W(CP_ME_RAM_DATAL, dev_priv->microcode[(i * 2) + 0]);
+       }
+}
+
+int radeon_ms_cp_finish(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       if (!dev_priv->cp_ready) {
+               return 0;
+       }
+       dev_priv->cp_ready = 0;
+       radeon_ms_wait_for_idle(dev);
+       DRM_INFO("[radeon_ms] cp idle\n");
+       radeon_ms_cp_stop(dev);
+
+       DRM_INFO("[radeon_ms] ring buffer %p\n", dev_priv->ring_buffer);
+       if (dev_priv->ring_buffer) {
+               drm_bo_kunmap(&dev_priv->ring_buffer_map);
+       }
+       dev_priv->ring_buffer = NULL;
+       DRM_INFO("[radeon_ms] ring buffer object %p\n", dev_priv->ring_buffer_object);
+       if (dev_priv->ring_buffer_object) {
+               mutex_lock(&dev->struct_mutex);
+               drm_bo_usage_deref_locked(&dev_priv->ring_buffer_object);
+               mutex_unlock(&dev->struct_mutex);
+       }
+       return 0;
+}
+
+int radeon_ms_cp_init(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+       int ret = 0;
+
+       dev_priv->cp_ready = -1;
+       if (dev_priv->microcode == NULL) {
+               DRM_INFO("[radeon_ms] no microcode not starting cp");
+               return 0;
+       }
+       /* we allocate an extra page for all write back stuff */
+       ret = drm_buffer_object_create(dev,
+                       dev_priv->ring_buffer_size +
+                       dev_priv->write_back_area_size,
+                       drm_bo_type_kernel,
+                       DRM_BO_FLAG_READ |
+                       DRM_BO_FLAG_WRITE |
+                       DRM_BO_FLAG_MEM_TT |
+                       DRM_BO_FLAG_NO_EVICT,
+                       DRM_BO_HINT_DONT_FENCE,
+                       1,
+                       0,
+                       &dev_priv->ring_buffer_object);
+       if (ret) {
+               return ret;
+       }
+       memset(&dev_priv->ring_buffer_map, 0, sizeof(struct drm_bo_kmap_obj));
+       ret = drm_bo_kmap(dev_priv->ring_buffer_object,
+                       dev_priv->ring_buffer_object->mem.mm_node->start,
+                       dev_priv->ring_buffer_object->mem.num_pages,
+                       &dev_priv->ring_buffer_map);
+       if (ret) {
+               DRM_ERROR("[radeon_ms] error mapping ring buffer: %d\n", ret);
+               return ret;
+       }
+       dev_priv->ring_buffer = dev_priv->ring_buffer_map.virtual; 
+       dev_priv->write_back_area =
+               &dev_priv->ring_buffer[dev_priv->ring_buffer_size >> 2];
+       /* setup write back offset */
+       state->scratch_umsk = 0x7; 
+       state->scratch_addr = 
+               REG_S(SCRATCH_ADDR, SCRATCH_ADDR,
+                               (dev_priv->ring_buffer_object->offset +
+                                dev_priv->ring_buffer_size +
+                                dev_priv->gpu_gart_start) >> 5);
+       MMIO_W(SCRATCH_ADDR, state->scratch_addr);
+       MMIO_W(SCRATCH_UMSK, REG_S(SCRATCH_UMSK, SCRATCH_UMSK, 0x7));
+       DRM_INFO("[radeon_ms] write back at 0x%08X in gpu space\n",
+                MMIO_R(SCRATCH_ADDR));
+       dev_priv->write_back = radeon_ms_test_write_back(dev);
+
+       /* stop cp so it's in know state */
+       radeon_ms_cp_stop(dev);
+       if (dev_priv->ring_rptr) {
+               DRM_INFO("[radeon_ms] failed to set cp read ptr to 0\n");
+       } else {
+               DRM_INFO("[radeon_ms] set cp read ptr to 0\n");
+       }
+       dev_priv->ring_mask = (dev_priv->ring_buffer_size / 4) - 1;
+
+       /* load microcode */
+       DRM_INFO("[radeon_ms] load microcode\n");
+       radeon_ms_load_mc(dev);
+       /* initialize CP registers */
+       state->cp_rb_cntl =
+               REG_S(CP_RB_CNTL, RB_BUFSZ,
+                               drm_order(dev_priv->ring_buffer_size / 8)) |
+               REG_S(CP_RB_CNTL, RB_BLKSZ, drm_order(4096 / 8)) |
+               REG_S(CP_RB_CNTL, MAX_FETCH, 2);
+       if (!dev_priv->write_back) {
+               state->cp_rb_cntl |= CP_RB_CNTL__RB_NO_UPDATE;
+       }
+       state->cp_rb_base =
+               REG_S(CP_RB_BASE, RB_BASE,
+                               (dev_priv->ring_buffer_object->offset +
+                                dev_priv->gpu_gart_start) >> 2);
+       /* read ptr writeback just after the
+        * 8 scratch registers 32 = 8*4 */
+       state->cp_rb_rptr_addr =
+               REG_S(CP_RB_RPTR_ADDR, RB_RPTR_ADDR,
+                               (dev_priv->ring_buffer_object->offset +
+                                dev_priv->ring_buffer_size + 32 +
+                                dev_priv->gpu_gart_start) >> 2);
+       state->cp_rb_wptr = dev_priv->ring_wptr;
+       state->cp_rb_wptr_delay =
+               REG_S(CP_RB_WPTR_DELAY, PRE_WRITE_TIMER, 64) |
+               REG_S(CP_RB_WPTR_DELAY, PRE_WRITE_LIMIT, 8);
+       state->cp_rb_wptr_delay = 0; 
+
+       radeon_ms_cp_restore(dev, state);
+       DRM_INFO("[radeon_ms] ring buffer at 0x%08X in gpu space\n",
+                MMIO_R(CP_RB_BASE));
+
+       /* compute free space */
+       dev_priv->ring_free = 0;
+       ret = radeon_ms_cp_wait(dev, 64);
+       if (ret) {
+               /* we shouldn't fail here */
+               DRM_INFO("[radeon_ms] failed to get ring free space\n");
+               return ret;
+       }
+       DRM_INFO("[radeon_ms] free ring size: %d\n", dev_priv->ring_free * 4);
+
+       MMIO_W(CP_CSQ_CNTL, REG_S(CP_CSQ_CNTL, CSQ_MODE,
+                               CSQ_MODE__CSQ_PRIBM_INDBM));
+       if (!radeon_ms_test_ring_buffer(dev)) {
+               DRM_INFO("[radeon_ms] cp doesn't work\n");
+               /* disable ring should wait idle before */
+               radeon_ms_cp_stop(dev);
+               return -EBUSY;
+       }
+       /* waaooo the cp is ready & working */
+       DRM_INFO("[radeon_ms] cp ready, enjoy\n");
+       dev_priv->cp_ready = 1;
+       return 0;
+}
+
+void radeon_ms_cp_restore(struct drm_device *dev, struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       radeon_ms_wait_for_idle(dev);
+       MMIO_W(SCRATCH_ADDR, state->scratch_addr);
+       MMIO_W(SCRATCH_UMSK, state->scratch_umsk);
+       MMIO_W(CP_RB_BASE, state->cp_rb_base);
+       MMIO_W(CP_RB_RPTR_ADDR, state->cp_rb_rptr_addr);
+       MMIO_W(CP_RB_WPTR_DELAY, state->cp_rb_wptr_delay);
+       MMIO_W(CP_RB_CNTL, state->cp_rb_cntl);
+       /* Sync everything up */
+       MMIO_W(ISYNC_CNTL, ISYNC_CNTL__ISYNC_ANY2D_IDLE3D |
+                          ISYNC_CNTL__ISYNC_ANY3D_IDLE2D |
+                          ISYNC_CNTL__ISYNC_WAIT_IDLEGUI |
+                          ISYNC_CNTL__ISYNC_CPSCRATCH_IDLEGUI);
+}
+
+void radeon_ms_cp_save(struct drm_device *dev, struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       state->scratch_addr = MMIO_R(SCRATCH_ADDR);
+       state->scratch_umsk = MMIO_R(SCRATCH_UMSK);
+       state->cp_rb_base = MMIO_R(CP_RB_BASE);
+       state->cp_rb_rptr_addr = MMIO_R(CP_RB_RPTR_ADDR);
+       state->cp_rb_wptr_delay = MMIO_R(CP_RB_WPTR_DELAY);
+       state->cp_rb_wptr = MMIO_R(CP_RB_WPTR);
+       state->cp_rb_cntl = MMIO_R(CP_RB_CNTL);
+}
+
+void radeon_ms_cp_stop(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       MMIO_W(CP_CSQ_CNTL, REG_S(CP_CSQ_CNTL, CSQ_MODE,
+                               CSQ_MODE__CSQ_PRIDIS_INDDIS));
+       MMIO_W(CP_RB_CNTL, CP_RB_CNTL__RB_RPTR_WR_ENA);
+       MMIO_W(CP_RB_RPTR_WR, 0);
+       MMIO_W(CP_RB_WPTR, 0);
+       DRM_UDELAY(5);
+       dev_priv->ring_wptr = dev_priv->ring_rptr = MMIO_R(CP_RB_RPTR);
+       MMIO_W(CP_RB_WPTR, dev_priv->ring_wptr);
+}
+
+int radeon_ms_cp_wait(struct drm_device *dev, int n)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       uint32_t i, last_rptr, p = 0;
+
+       last_rptr = MMIO_R(CP_RB_RPTR);
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               dev_priv->ring_rptr = MMIO_R(CP_RB_RPTR);
+               if (last_rptr != dev_priv->ring_rptr) {
+                       /* the ring is progressing no lockup */
+                       p = 1;
+               }
+               dev_priv->ring_free = (((int)dev_priv->ring_rptr) -
+                                      ((int)dev_priv->ring_wptr));
+               if (dev_priv->ring_free <= 0)
+                       dev_priv->ring_free += (dev_priv->ring_buffer_size / 4);
+               if (dev_priv->ring_free > n)
+                       return 0;
+               last_rptr = dev_priv->ring_rptr;
+               DRM_UDELAY(1);
+       }
+       if (p) {
+               DRM_INFO("[radeon_ms] timed out waiting free slot\n");
+       } else {
+               DRM_INFO("[radeon_ms] cp have lickely locked up\n");
+       }
+       return -EBUSY;
+}
+
+int radeon_ms_ring_emit(struct drm_device *dev, uint32_t *cmd, uint32_t count)
+{
+       static spinlock_t ring_lock = SPIN_LOCK_UNLOCKED;
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       uint32_t i = 0;
+
+       if (!count)
+               return -EINVAL;
+
+       spin_lock(&ring_lock);
+       if (dev_priv->ring_free <= (count)) {
+               spin_unlock(&ring_lock);
+               return -EBUSY;
+       }
+       dev_priv->ring_free -= count;
+       for (i = 0; i < count; i++) {
+               dev_priv->ring_buffer[dev_priv->ring_wptr] = cmd[i];
+               dev_priv->ring_wptr++;
+               dev_priv->ring_wptr &= dev_priv->ring_mask;
+       }
+       /* commit ring */
+       DRM_MEMORYBARRIER();
+       MMIO_W(CP_RB_WPTR, REG_S(CP_RB_WPTR, RB_WPTR, dev_priv->ring_wptr));
+       /* read from PCI bus to ensure correct posting */
+       MMIO_R(CP_RB_WPTR);
+       spin_unlock(&ring_lock);
+       return 0;
+}
diff --git a/shared-core/radeon_ms_cp_mc.c b/shared-core/radeon_ms_cp_mc.c
new file mode 100644 (file)
index 0000000..f0397d8
--- /dev/null
@@ -0,0 +1,801 @@
+/*
+ * Copyright 2007  Advanced Micro Devices, Inc.
+ *
+ * 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
+ * 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 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ */
+#include "radeon_ms.h"
+
+/* CP microcode (from ATI) */
+
+const uint32_t radeon_cp_microcode[] = {
+       0x21007000, 0000000000,
+       0x20007000, 0000000000,
+       0x000000b4, 0x00000004,
+       0x000000b8, 0x00000004,
+       0x6f5b4d4c, 0000000000,
+       0x4c4c427f, 0000000000,
+       0x5b568a92, 0000000000,
+       0x4ca09c6d, 0000000000,
+       0xad4c4c4c, 0000000000,
+       0x4ce1af3d, 0000000000,
+       0xd8afafaf, 0000000000,
+       0xd64c4cdc, 0000000000,
+       0x4cd10d10, 0000000000,
+       0x000f0000, 0x00000016,
+       0x362f242d, 0000000000,
+       0x00000012, 0x00000004,
+       0x000f0000, 0x00000016,
+       0x362f282d, 0000000000,
+       0x000380e7, 0x00000002,
+       0x04002c97, 0x00000002,
+       0x000f0001, 0x00000016,
+       0x333a3730, 0000000000,
+       0x000077ef, 0x00000002,
+       0x00061000, 0x00000002,
+       0x00000021, 0x0000001a,
+       0x00004000, 0x0000001e,
+       0x00061000, 0x00000002,
+       0x00000021, 0x0000001a,
+       0x00004000, 0x0000001e,
+       0x00061000, 0x00000002,
+       0x00000021, 0x0000001a,
+       0x00004000, 0x0000001e,
+       0x00000017, 0x00000004,
+       0x0003802b, 0x00000002,
+       0x040067e0, 0x00000002,
+       0x00000017, 0x00000004,
+       0x000077e0, 0x00000002,
+       0x00065000, 0x00000002,
+       0x000037e1, 0x00000002,
+       0x040067e1, 0x00000006,
+       0x000077e0, 0x00000002,
+       0x000077e1, 0x00000002,
+       0x000077e1, 0x00000006,
+       0xffffffff, 0000000000,
+       0x10000000, 0000000000,
+       0x0003802b, 0x00000002,
+       0x040067e0, 0x00000006,
+       0x00007675, 0x00000002,
+       0x00007676, 0x00000002,
+       0x00007677, 0x00000002,
+       0x00007678, 0x00000006,
+       0x0003802c, 0x00000002,
+       0x04002676, 0x00000002,
+       0x00007677, 0x00000002,
+       0x00007678, 0x00000006,
+       0x0000002f, 0x00000018,
+       0x0000002f, 0x00000018,
+       0000000000, 0x00000006,
+       0x00000030, 0x00000018,
+       0x00000030, 0x00000018,
+       0000000000, 0x00000006,
+       0x01605000, 0x00000002,
+       0x00065000, 0x00000002,
+       0x00098000, 0x00000002,
+       0x00061000, 0x00000002,
+       0x64c0603e, 0x00000004,
+       0x000380e6, 0x00000002,
+       0x040025c5, 0x00000002,
+       0x00080000, 0x00000016,
+       0000000000, 0000000000,
+       0x0400251d, 0x00000002,
+       0x00007580, 0x00000002,
+       0x00067581, 0x00000002,
+       0x04002580, 0x00000002,
+       0x00067581, 0x00000002,
+       0x00000049, 0x00000004,
+       0x00005000, 0000000000,
+       0x000380e6, 0x00000002,
+       0x040025c5, 0x00000002,
+       0x00061000, 0x00000002,
+       0x0000750e, 0x00000002,
+       0x00019000, 0x00000002,
+       0x00011055, 0x00000014,
+       0x00000055, 0x00000012,
+       0x0400250f, 0x00000002,
+       0x0000504f, 0x00000004,
+       0x000380e6, 0x00000002,
+       0x040025c5, 0x00000002,
+       0x00007565, 0x00000002,
+       0x00007566, 0x00000002,
+       0x00000058, 0x00000004,
+       0x000380e6, 0x00000002,
+       0x040025c5, 0x00000002,
+       0x01e655b4, 0x00000002,
+       0x4401b0e4, 0x00000002,
+       0x01c110e4, 0x00000002,
+       0x26667066, 0x00000018,
+       0x040c2565, 0x00000002,
+       0x00000066, 0x00000018,
+       0x04002564, 0x00000002,
+       0x00007566, 0x00000002,
+       0x0000005d, 0x00000004,
+       0x00401069, 0x00000008,
+       0x00101000, 0x00000002,
+       0x000d80ff, 0x00000002,
+       0x0080006c, 0x00000008,
+       0x000f9000, 0x00000002,
+       0x000e00ff, 0x00000002,
+       0000000000, 0x00000006,
+       0x0000008f, 0x00000018,
+       0x0000005b, 0x00000004,
+       0x000380e6, 0x00000002,
+       0x040025c5, 0x00000002,
+       0x00007576, 0x00000002,
+       0x00065000, 0x00000002,
+       0x00009000, 0x00000002,
+       0x00041000, 0x00000002,
+       0x0c00350e, 0x00000002,
+       0x00049000, 0x00000002,
+       0x00051000, 0x00000002,
+       0x01e785f8, 0x00000002,
+       0x00200000, 0x00000002,
+       0x0060007e, 0x0000000c,
+       0x00007563, 0x00000002,
+       0x006075f0, 0x00000021,
+       0x20007073, 0x00000004,
+       0x00005073, 0x00000004,
+       0x000380e6, 0x00000002,
+       0x040025c5, 0x00000002,
+       0x00007576, 0x00000002,
+       0x00007577, 0x00000002,
+       0x0000750e, 0x00000002,
+       0x0000750f, 0x00000002,
+       0x00a05000, 0x00000002,
+       0x00600083, 0x0000000c,
+       0x006075f0, 0x00000021,
+       0x000075f8, 0x00000002,
+       0x00000083, 0x00000004,
+       0x000a750e, 0x00000002,
+       0x000380e6, 0x00000002,
+       0x040025c5, 0x00000002,
+       0x0020750f, 0x00000002,
+       0x00600086, 0x00000004,
+       0x00007570, 0x00000002,
+       0x00007571, 0x00000002,
+       0x00007572, 0x00000006,
+       0x000380e6, 0x00000002,
+       0x040025c5, 0x00000002,
+       0x00005000, 0x00000002,
+       0x00a05000, 0x00000002,
+       0x00007568, 0x00000002,
+       0x00061000, 0x00000002,
+       0x00000095, 0x0000000c,
+       0x00058000, 0x00000002,
+       0x0c607562, 0x00000002,
+       0x00000097, 0x00000004,
+       0x000380e6, 0x00000002,
+       0x040025c5, 0x00000002,
+       0x00600096, 0x00000004,
+       0x400070e5, 0000000000,
+       0x000380e6, 0x00000002,
+       0x040025c5, 0x00000002,
+       0x000380e5, 0x00000002,
+       0x000000a8, 0x0000001c,
+       0x000650aa, 0x00000018,
+       0x040025bb, 0x00000002,
+       0x000610ab, 0x00000018,
+       0x040075bc, 0000000000,
+       0x000075bb, 0x00000002,
+       0x000075bc, 0000000000,
+       0x00090000, 0x00000006,
+       0x00090000, 0x00000002,
+       0x000d8002, 0x00000006,
+       0x00007832, 0x00000002,
+       0x00005000, 0x00000002,
+       0x000380e7, 0x00000002,
+       0x04002c97, 0x00000002,
+       0x00007820, 0x00000002,
+       0x00007821, 0x00000002,
+       0x00007800, 0000000000,
+       0x01200000, 0x00000002,
+       0x20077000, 0x00000002,
+       0x01200000, 0x00000002,
+       0x20007000, 0x00000002,
+       0x00061000, 0x00000002,
+       0x0120751b, 0x00000002,
+       0x8040750a, 0x00000002,
+       0x8040750b, 0x00000002,
+       0x00110000, 0x00000002,
+       0x000380e5, 0x00000002,
+       0x000000c6, 0x0000001c,
+       0x000610ab, 0x00000018,
+       0x844075bd, 0x00000002,
+       0x000610aa, 0x00000018,
+       0x840075bb, 0x00000002,
+       0x000610ab, 0x00000018,
+       0x844075bc, 0x00000002,
+       0x000000c9, 0x00000004,
+       0x804075bd, 0x00000002,
+       0x800075bb, 0x00000002,
+       0x804075bc, 0x00000002,
+       0x00108000, 0x00000002,
+       0x01400000, 0x00000002,
+       0x006000cd, 0x0000000c,
+       0x20c07000, 0x00000020,
+       0x000000cf, 0x00000012,
+       0x00800000, 0x00000006,
+       0x0080751d, 0x00000006,
+       0000000000, 0000000000,
+       0x0000775c, 0x00000002,
+       0x00a05000, 0x00000002,
+       0x00661000, 0x00000002,
+       0x0460275d, 0x00000020,
+       0x00004000, 0000000000,
+       0x01e00830, 0x00000002,
+       0x21007000, 0000000000,
+       0x6464614d, 0000000000,
+       0x69687420, 0000000000,
+       0x00000073, 0000000000,
+       0000000000, 0000000000,
+       0x00005000, 0x00000002,
+       0x000380d0, 0x00000002,
+       0x040025e0, 0x00000002,
+       0x000075e1, 0000000000,
+       0x00000001, 0000000000,
+       0x000380e0, 0x00000002,
+       0x04002394, 0x00000002,
+       0x00005000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0x00000008, 0000000000,
+       0x00000004, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+};
+
+const uint32_t r200_cp_microcode[] = {
+       0x21007000, 0000000000,
+       0x20007000, 0000000000,
+       0x000000ab, 0x00000004,
+       0x000000af, 0x00000004,
+       0x66544a49, 0000000000,
+       0x49494174, 0000000000,
+       0x54517d83, 0000000000,
+       0x498d8b64, 0000000000,
+       0x49494949, 0000000000,
+       0x49da493c, 0000000000,
+       0x49989898, 0000000000,
+       0xd34949d5, 0000000000,
+       0x9dc90e11, 0000000000,
+       0xce9b9b9b, 0000000000,
+       0x000f0000, 0x00000016,
+       0x352e232c, 0000000000,
+       0x00000013, 0x00000004,
+       0x000f0000, 0x00000016,
+       0x352e272c, 0000000000,
+       0x000f0001, 0x00000016,
+       0x3239362f, 0000000000,
+       0x000077ef, 0x00000002,
+       0x00061000, 0x00000002,
+       0x00000020, 0x0000001a,
+       0x00004000, 0x0000001e,
+       0x00061000, 0x00000002,
+       0x00000020, 0x0000001a,
+       0x00004000, 0x0000001e,
+       0x00061000, 0x00000002,
+       0x00000020, 0x0000001a,
+       0x00004000, 0x0000001e,
+       0x00000016, 0x00000004,
+       0x0003802a, 0x00000002,
+       0x040067e0, 0x00000002,
+       0x00000016, 0x00000004,
+       0x000077e0, 0x00000002,
+       0x00065000, 0x00000002,
+       0x000037e1, 0x00000002,
+       0x040067e1, 0x00000006,
+       0x000077e0, 0x00000002,
+       0x000077e1, 0x00000002,
+       0x000077e1, 0x00000006,
+       0xffffffff, 0000000000,
+       0x10000000, 0000000000,
+       0x0003802a, 0x00000002,
+       0x040067e0, 0x00000006,
+       0x00007675, 0x00000002,
+       0x00007676, 0x00000002,
+       0x00007677, 0x00000002,
+       0x00007678, 0x00000006,
+       0x0003802b, 0x00000002,
+       0x04002676, 0x00000002,
+       0x00007677, 0x00000002,
+       0x00007678, 0x00000006,
+       0x0000002e, 0x00000018,
+       0x0000002e, 0x00000018,
+       0000000000, 0x00000006,
+       0x0000002f, 0x00000018,
+       0x0000002f, 0x00000018,
+       0000000000, 0x00000006,
+       0x01605000, 0x00000002,
+       0x00065000, 0x00000002,
+       0x00098000, 0x00000002,
+       0x00061000, 0x00000002,
+       0x64c0603d, 0x00000004,
+       0x00080000, 0x00000016,
+       0000000000, 0000000000,
+       0x0400251d, 0x00000002,
+       0x00007580, 0x00000002,
+       0x00067581, 0x00000002,
+       0x04002580, 0x00000002,
+       0x00067581, 0x00000002,
+       0x00000046, 0x00000004,
+       0x00005000, 0000000000,
+       0x00061000, 0x00000002,
+       0x0000750e, 0x00000002,
+       0x00019000, 0x00000002,
+       0x00011055, 0x00000014,
+       0x00000055, 0x00000012,
+       0x0400250f, 0x00000002,
+       0x0000504a, 0x00000004,
+       0x00007565, 0x00000002,
+       0x00007566, 0x00000002,
+       0x00000051, 0x00000004,
+       0x01e655b4, 0x00000002,
+       0x4401b0dc, 0x00000002,
+       0x01c110dc, 0x00000002,
+       0x2666705d, 0x00000018,
+       0x040c2565, 0x00000002,
+       0x0000005d, 0x00000018,
+       0x04002564, 0x00000002,
+       0x00007566, 0x00000002,
+       0x00000054, 0x00000004,
+       0x00401060, 0x00000008,
+       0x00101000, 0x00000002,
+       0x000d80ff, 0x00000002,
+       0x00800063, 0x00000008,
+       0x000f9000, 0x00000002,
+       0x000e00ff, 0x00000002,
+       0000000000, 0x00000006,
+       0x00000080, 0x00000018,
+       0x00000054, 0x00000004,
+       0x00007576, 0x00000002,
+       0x00065000, 0x00000002,
+       0x00009000, 0x00000002,
+       0x00041000, 0x00000002,
+       0x0c00350e, 0x00000002,
+       0x00049000, 0x00000002,
+       0x00051000, 0x00000002,
+       0x01e785f8, 0x00000002,
+       0x00200000, 0x00000002,
+       0x00600073, 0x0000000c,
+       0x00007563, 0x00000002,
+       0x006075f0, 0x00000021,
+       0x20007068, 0x00000004,
+       0x00005068, 0x00000004,
+       0x00007576, 0x00000002,
+       0x00007577, 0x00000002,
+       0x0000750e, 0x00000002,
+       0x0000750f, 0x00000002,
+       0x00a05000, 0x00000002,
+       0x00600076, 0x0000000c,
+       0x006075f0, 0x00000021,
+       0x000075f8, 0x00000002,
+       0x00000076, 0x00000004,
+       0x000a750e, 0x00000002,
+       0x0020750f, 0x00000002,
+       0x00600079, 0x00000004,
+       0x00007570, 0x00000002,
+       0x00007571, 0x00000002,
+       0x00007572, 0x00000006,
+       0x00005000, 0x00000002,
+       0x00a05000, 0x00000002,
+       0x00007568, 0x00000002,
+       0x00061000, 0x00000002,
+       0x00000084, 0x0000000c,
+       0x00058000, 0x00000002,
+       0x0c607562, 0x00000002,
+       0x00000086, 0x00000004,
+       0x00600085, 0x00000004,
+       0x400070dd, 0000000000,
+       0x000380dd, 0x00000002,
+       0x00000093, 0x0000001c,
+       0x00065095, 0x00000018,
+       0x040025bb, 0x00000002,
+       0x00061096, 0x00000018,
+       0x040075bc, 0000000000,
+       0x000075bb, 0x00000002,
+       0x000075bc, 0000000000,
+       0x00090000, 0x00000006,
+       0x00090000, 0x00000002,
+       0x000d8002, 0x00000006,
+       0x00005000, 0x00000002,
+       0x00007821, 0x00000002,
+       0x00007800, 0000000000,
+       0x00007821, 0x00000002,
+       0x00007800, 0000000000,
+       0x01665000, 0x00000002,
+       0x000a0000, 0x00000002,
+       0x000671cc, 0x00000002,
+       0x0286f1cd, 0x00000002,
+       0x000000a3, 0x00000010,
+       0x21007000, 0000000000,
+       0x000000aa, 0x0000001c,
+       0x00065000, 0x00000002,
+       0x000a0000, 0x00000002,
+       0x00061000, 0x00000002,
+       0x000b0000, 0x00000002,
+       0x38067000, 0x00000002,
+       0x000a00a6, 0x00000004,
+       0x20007000, 0000000000,
+       0x01200000, 0x00000002,
+       0x20077000, 0x00000002,
+       0x01200000, 0x00000002,
+       0x20007000, 0000000000,
+       0x00061000, 0x00000002,
+       0x0120751b, 0x00000002,
+       0x8040750a, 0x00000002,
+       0x8040750b, 0x00000002,
+       0x00110000, 0x00000002,
+       0x000380dd, 0x00000002,
+       0x000000bd, 0x0000001c,
+       0x00061096, 0x00000018,
+       0x844075bd, 0x00000002,
+       0x00061095, 0x00000018,
+       0x840075bb, 0x00000002,
+       0x00061096, 0x00000018,
+       0x844075bc, 0x00000002,
+       0x000000c0, 0x00000004,
+       0x804075bd, 0x00000002,
+       0x800075bb, 0x00000002,
+       0x804075bc, 0x00000002,
+       0x00108000, 0x00000002,
+       0x01400000, 0x00000002,
+       0x006000c4, 0x0000000c,
+       0x20c07000, 0x00000020,
+       0x000000c6, 0x00000012,
+       0x00800000, 0x00000006,
+       0x0080751d, 0x00000006,
+       0x000025bb, 0x00000002,
+       0x000040c0, 0x00000004,
+       0x0000775c, 0x00000002,
+       0x00a05000, 0x00000002,
+       0x00661000, 0x00000002,
+       0x0460275d, 0x00000020,
+       0x00004000, 0000000000,
+       0x00007999, 0x00000002,
+       0x00a05000, 0x00000002,
+       0x00661000, 0x00000002,
+       0x0460299b, 0x00000020,
+       0x00004000, 0000000000,
+       0x01e00830, 0x00000002,
+       0x21007000, 0000000000,
+       0x00005000, 0x00000002,
+       0x00038042, 0x00000002,
+       0x040025e0, 0x00000002,
+       0x000075e1, 0000000000,
+       0x00000001, 0000000000,
+       0x000380d9, 0x00000002,
+       0x04007394, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+       0000000000, 0000000000,
+};
+
+const uint32_t r300_cp_microcode[] = {
+        0x4200e000, 0000000000,
+        0x4000e000, 0000000000,
+        0x000000af, 0x00000008,
+        0x000000b3, 0x00000008,
+        0x6c5a504f, 0000000000,
+        0x4f4f497a, 0000000000,
+        0x5a578288, 0000000000,
+        0x4f91906a, 0000000000,
+        0x4f4f4f4f, 0000000000,
+        0x4fe24f44, 0000000000,
+        0x4f9c9c9c, 0000000000,
+        0xdc4f4fde, 0000000000,
+        0xa1cd4f4f, 0000000000,
+        0xd29d9d9d, 0000000000,
+        0x4f0f9fd7, 0000000000,
+        0x000ca000, 0x00000004,
+        0x000d0012, 0x00000038,
+        0x0000e8b4, 0x00000004,
+        0x000d0014, 0x00000038,
+        0x0000e8b6, 0x00000004,
+        0x000d0016, 0x00000038,
+        0x0000e854, 0x00000004,
+        0x000d0018, 0x00000038,
+        0x0000e855, 0x00000004,
+        0x000d001a, 0x00000038,
+        0x0000e856, 0x00000004,
+        0x000d001c, 0x00000038,
+        0x0000e857, 0x00000004,
+        0x000d001e, 0x00000038,
+        0x0000e824, 0x00000004,
+        0x000d0020, 0x00000038,
+        0x0000e825, 0x00000004,
+        0x000d0022, 0x00000038,
+        0x0000e830, 0x00000004,
+        0x000d0024, 0x00000038,
+        0x0000f0c0, 0x00000004,
+        0x000d0026, 0x00000038,
+        0x0000f0c1, 0x00000004,
+        0x000d0028, 0x00000038,
+        0x0000f041, 0x00000004,
+        0x000d002a, 0x00000038,
+        0x0000f184, 0x00000004,
+        0x000d002c, 0x00000038,
+        0x0000f185, 0x00000004,
+        0x000d002e, 0x00000038,
+        0x0000f186, 0x00000004,
+        0x000d0030, 0x00000038,
+        0x0000f187, 0x00000004,
+        0x000d0032, 0x00000038,
+        0x0000f180, 0x00000004,
+        0x000d0034, 0x00000038,
+        0x0000f393, 0x00000004,
+        0x000d0036, 0x00000038,
+        0x0000f38a, 0x00000004,
+        0x000d0038, 0x00000038,
+        0x0000f38e, 0x00000004,
+        0x0000e821, 0x00000004,
+        0x0140a000, 0x00000004,
+        0x00000043, 0x00000018,
+        0x00cce800, 0x00000004,
+        0x001b0001, 0x00000004,
+        0x08004800, 0x00000004,
+        0x001b0001, 0x00000004,
+        0x08004800, 0x00000004,
+        0x001b0001, 0x00000004,
+        0x08004800, 0x00000004,
+        0x0000003a, 0x00000008,
+        0x0000a000, 0000000000,
+        0x02c0a000, 0x00000004,
+        0x000ca000, 0x00000004,
+        0x00130000, 0x00000004,
+        0x000c2000, 0x00000004,
+        0xc980c045, 0x00000008,
+        0x2000451d, 0x00000004,
+        0x0000e580, 0x00000004,
+        0x000ce581, 0x00000004,
+        0x08004580, 0x00000004,
+        0x000ce581, 0x00000004,
+        0x0000004c, 0x00000008,
+        0x0000a000, 0000000000,
+        0x000c2000, 0x00000004,
+        0x0000e50e, 0x00000004,
+        0x00032000, 0x00000004,
+        0x00022056, 0x00000028,
+        0x00000056, 0x00000024,
+        0x0800450f, 0x00000004,
+        0x0000a050, 0x00000008,
+        0x0000e565, 0x00000004,
+        0x0000e566, 0x00000004,
+        0x00000057, 0x00000008,
+        0x03cca5b4, 0x00000004,
+        0x05432000, 0x00000004,
+        0x00022000, 0x00000004,
+        0x4ccce063, 0x00000030,
+        0x08274565, 0x00000004,
+        0x00000063, 0x00000030,
+        0x08004564, 0x00000004,
+        0x0000e566, 0x00000004,
+        0x0000005a, 0x00000008,
+        0x00802066, 0x00000010,
+        0x00202000, 0x00000004,
+        0x001b00ff, 0x00000004,
+        0x01000069, 0x00000010,
+        0x001f2000, 0x00000004,
+        0x001c00ff, 0x00000004,
+        0000000000, 0x0000000c,
+        0x00000085, 0x00000030,
+        0x0000005a, 0x00000008,
+        0x0000e576, 0x00000004,
+        0x000ca000, 0x00000004,
+        0x00012000, 0x00000004,
+        0x00082000, 0x00000004,
+        0x1800650e, 0x00000004,
+        0x00092000, 0x00000004,
+        0x000a2000, 0x00000004,
+        0x000f0000, 0x00000004,
+        0x00400000, 0x00000004,
+        0x00000079, 0x00000018,
+        0x0000e563, 0x00000004,
+        0x00c0e5f9, 0x000000c2,
+        0x0000006e, 0x00000008,
+        0x0000a06e, 0x00000008,
+        0x0000e576, 0x00000004,
+        0x0000e577, 0x00000004,
+        0x0000e50e, 0x00000004,
+        0x0000e50f, 0x00000004,
+        0x0140a000, 0x00000004,
+        0x0000007c, 0x00000018,
+        0x00c0e5f9, 0x000000c2,
+        0x0000007c, 0x00000008,
+        0x0014e50e, 0x00000004,
+        0x0040e50f, 0x00000004,
+        0x00c0007f, 0x00000008,
+        0x0000e570, 0x00000004,
+        0x0000e571, 0x00000004,
+        0x0000e572, 0x0000000c,
+        0x0000a000, 0x00000004,
+        0x0140a000, 0x00000004,
+        0x0000e568, 0x00000004,
+        0x000c2000, 0x00000004,
+        0x00000089, 0x00000018,
+        0x000b0000, 0x00000004,
+        0x18c0e562, 0x00000004,
+        0x0000008b, 0x00000008,
+        0x00c0008a, 0x00000008,
+        0x000700e4, 0x00000004,
+        0x00000097, 0x00000038,
+        0x000ca099, 0x00000030,
+        0x080045bb, 0x00000004,
+        0x000c209a, 0x00000030,
+        0x0800e5bc, 0000000000,
+        0x0000e5bb, 0x00000004,
+        0x0000e5bc, 0000000000,
+        0x00120000, 0x0000000c,
+        0x00120000, 0x00000004,
+        0x001b0002, 0x0000000c,
+        0x0000a000, 0x00000004,
+        0x0000e821, 0x00000004,
+        0x0000e800, 0000000000,
+        0x0000e821, 0x00000004,
+        0x0000e82e, 0000000000,
+        0x02cca000, 0x00000004,
+        0x00140000, 0x00000004,
+        0x000ce1cc, 0x00000004,
+        0x050de1cd, 0x00000004,
+        0x000000a7, 0x00000020,
+        0x4200e000, 0000000000,
+        0x000000ae, 0x00000038,
+        0x000ca000, 0x00000004,
+        0x00140000, 0x00000004,
+        0x000c2000, 0x00000004,
+        0x00160000, 0x00000004,
+        0x700ce000, 0x00000004,
+        0x001400aa, 0x00000008,
+        0x4000e000, 0000000000,
+        0x02400000, 0x00000004,
+        0x400ee000, 0x00000004,
+        0x02400000, 0x00000004,
+        0x4000e000, 0000000000,
+        0x000c2000, 0x00000004,
+        0x0240e51b, 0x00000004,
+        0x0080e50a, 0x00000005,
+        0x0080e50b, 0x00000005,
+        0x00220000, 0x00000004,
+        0x000700e4, 0x00000004,
+        0x000000c1, 0x00000038,
+        0x000c209a, 0x00000030,
+        0x0880e5bd, 0x00000005,
+        0x000c2099, 0x00000030,
+        0x0800e5bb, 0x00000005,
+        0x000c209a, 0x00000030,
+        0x0880e5bc, 0x00000005,
+        0x000000c4, 0x00000008,
+        0x0080e5bd, 0x00000005,
+        0x0000e5bb, 0x00000005,
+        0x0080e5bc, 0x00000005,
+        0x00210000, 0x00000004,
+        0x02800000, 0x00000004,
+        0x00c000c8, 0x00000018,
+        0x4180e000, 0x00000040,
+        0x000000ca, 0x00000024,
+        0x01000000, 0x0000000c,
+        0x0100e51d, 0x0000000c,
+        0x000045bb, 0x00000004,
+        0x000080c4, 0x00000008,
+        0x0000f3ce, 0x00000004,
+        0x0140a000, 0x00000004,
+        0x00cc2000, 0x00000004,
+        0x08c053cf, 0x00000040,
+        0x00008000, 0000000000,
+        0x0000f3d2, 0x00000004,
+        0x0140a000, 0x00000004,
+        0x00cc2000, 0x00000004,
+        0x08c053d3, 0x00000040,
+        0x00008000, 0000000000,
+        0x0000f39d, 0x00000004,
+        0x0140a000, 0x00000004,
+        0x00cc2000, 0x00000004,
+        0x08c0539e, 0x00000040,
+        0x00008000, 0000000000,
+        0x03c00830, 0x00000004,
+        0x4200e000, 0000000000,
+        0x0000a000, 0x00000004,
+        0x200045e0, 0x00000004,
+        0x0000e5e1, 0000000000,
+        0x00000001, 0000000000,
+        0x000700e1, 0x00000004,
+        0x0800e394, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+        0000000000, 0000000000,
+};
diff --git a/shared-core/radeon_ms_crtc.c b/shared-core/radeon_ms_crtc.c
new file mode 100644 (file)
index 0000000..b238385
--- /dev/null
@@ -0,0 +1,803 @@
+/*
+ * Copyright Â© 2007 Alex Deucher
+ * Copyright Â© 2007 Dave Airlie
+ * Copyright Â© 2007 Michel Dänzer
+ * Copyright Â© 2007 Jerome Glisse
+ *
+ * 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.
+ */
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "radeon_ms.h"
+
+static void radeon_pll1_init(struct drm_radeon_private *dev_priv,
+                            struct radeon_state *state);
+static void radeon_pll1_restore(struct drm_radeon_private *dev_priv,
+                               struct radeon_state *state);
+static void radeon_pll1_save(struct drm_radeon_private *dev_priv,
+                            struct radeon_state *state);
+static void radeon_ms_crtc_load_lut(struct drm_crtc *crtc);
+
+/**
+ * radeon_ms_crtc1_init - initialize CRTC state
+ * @dev_priv: radeon private structure
+ * @state: state structure to initialize to default value
+ *
+ * Initialize CRTC state to default values
+ */
+static void radeon_ms_crtc1_init(struct drm_radeon_private *dev_priv,
+                                struct radeon_state *state)
+{
+       state->surface_cntl = SURFACE_CNTL__SURF_TRANSLATION_DIS;
+       state->surface0_info = 0;
+       state->surface0_lower_bound = 0;
+       state->surface0_upper_bound = 0;
+       state->surface1_info = 0;
+       state->surface1_lower_bound = 0;
+       state->surface1_upper_bound = 0;
+       state->surface2_info = 0;
+       state->surface2_lower_bound = 0;
+       state->surface2_upper_bound = 0;
+       state->surface3_info = 0;
+       state->surface3_lower_bound = 0;
+       state->surface3_upper_bound = 0;
+       state->surface4_info = 0;
+       state->surface4_lower_bound = 0;
+       state->surface4_upper_bound = 0;
+       state->surface5_info = 0;
+       state->surface5_lower_bound = 0;
+       state->surface5_upper_bound = 0;
+       state->surface6_info = 0;
+       state->surface6_lower_bound = 0;
+       state->surface6_upper_bound = 0;
+       state->surface7_info = 0;
+       state->surface7_lower_bound = 0;
+       state->surface7_upper_bound = 0;
+       state->crtc_gen_cntl = CRTC_GEN_CNTL__CRTC_EXT_DISP_EN |
+                              CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B;
+       state->crtc_ext_cntl = CRTC_EXT_CNTL__VGA_ATI_LINEAR |
+                              CRTC_EXT_CNTL__VGA_XCRT_CNT_EN |
+                              CRTC_EXT_CNTL__CRT_ON;
+       state->crtc_h_total_disp = 0;
+       state->crtc_h_sync_strt_wid = 0;
+       state->crtc_v_total_disp = 0;
+       state->crtc_v_sync_strt_wid = 0;
+       state->crtc_offset = 0;
+       state->crtc_pitch = 0;
+       state->crtc_more_cntl = 0;
+       state->crtc_tile_x0_y0 = 0;
+       state->crtc_offset_cntl = 0;
+       switch (dev_priv->family) {
+       case CHIP_R100:
+       case CHIP_R200:
+       case CHIP_RV200:
+       case CHIP_RV250:
+       case CHIP_RV280:
+       case CHIP_RS300:
+               break;
+       case CHIP_R300:
+       case CHIP_R350:
+       case CHIP_R360:
+       case CHIP_RV350:
+       case CHIP_RV370:
+       case CHIP_RV380:
+       case CHIP_RS400:
+       case CHIP_RV410:
+       case CHIP_R420:
+       case CHIP_R430:
+       case CHIP_R480:
+               state->crtc_offset_cntl |= REG_S(CRTC_OFFSET_CNTL,
+                               CRTC_MICRO_TILE_BUFFER_MODE,
+                               CRTC_MICRO_TILE_BUFFER_MODE__DIS);
+               break;
+       default:
+               DRM_ERROR("Unknown radeon family, aborting\n");
+               return;
+       }
+       radeon_pll1_init(dev_priv, state);
+}
+
+/**
+ * radeon_pll1_init - initialize PLL1 state
+ * @dev_priv: radeon private structure
+ * @state: state structure to initialize to default value
+ *
+ * Initialize PLL1 state to default values
+ */
+static void radeon_pll1_init(struct drm_radeon_private *dev_priv,
+                            struct radeon_state *state)
+{
+       state->clock_cntl_index = 0;
+       state->ppll_cntl = PPLL_R(PPLL_CNTL);
+       state->ppll_cntl |= PPLL_CNTL__PPLL_ATOMIC_UPDATE_EN |
+               PPLL_CNTL__PPLL_ATOMIC_UPDATE_SYNC |
+               PPLL_CNTL__PPLL_VGA_ATOMIC_UPDATE_EN;
+       state->ppll_cntl &= ~PPLL_CNTL__PPLL_TST_EN;
+       state->ppll_cntl &= ~PPLL_CNTL__PPLL_TCPOFF;
+       state->ppll_cntl &= ~PPLL_CNTL__PPLL_TVCOMAX;
+       state->ppll_cntl &= ~PPLL_CNTL__PPLL_DISABLE_AUTO_RESET;
+       state->ppll_ref_div = 0;
+       state->ppll_ref_div = REG_S(PPLL_REF_DIV, PPLL_REF_DIV, 12) |
+               REG_S(PPLL_REF_DIV, PPLL_REF_DIV_SRC, PPLL_REF_DIV_SRC__XTALIN);
+       state->ppll_div_0 = 0;
+       state->ppll_div_1 = 0;
+       state->ppll_div_2 = 0;
+       state->ppll_div_3 = 0;
+       state->vclk_ecp_cntl = 0;
+       state->htotal_cntl = 0;
+}
+
+/**
+ * radeon_ms_crtc1_restore - restore CRTC state
+ * @dev_priv: radeon private structure
+ * @state: CRTC state to restore
+ */
+void radeon_ms_crtc1_restore(struct drm_device *dev, struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       /* We prevent the CRTC from hitting the memory controller until
+        * fully programmed
+        */
+       MMIO_W(CRTC_GEN_CNTL, ~CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B &
+                       state->crtc_gen_cntl);
+       MMIO_W(CRTC_EXT_CNTL, CRTC_EXT_CNTL__CRTC_VSYNC_DIS |
+                       CRTC_EXT_CNTL__CRTC_HSYNC_DIS |
+                       CRTC_EXT_CNTL__CRTC_DISPLAY_DIS |
+                       state->crtc_ext_cntl);
+       MMIO_W(SURFACE_CNTL, state->surface_cntl);
+       MMIO_W(SURFACE0_INFO, state->surface0_info);
+       MMIO_W(SURFACE0_LOWER_BOUND, state->surface0_lower_bound);
+       MMIO_W(SURFACE0_UPPER_BOUND, state->surface0_upper_bound);
+       MMIO_W(SURFACE1_INFO, state->surface1_info);
+       MMIO_W(SURFACE1_LOWER_BOUND, state->surface1_lower_bound);
+       MMIO_W(SURFACE1_UPPER_BOUND, state->surface1_upper_bound);
+       MMIO_W(SURFACE2_INFO, state->surface2_info);
+       MMIO_W(SURFACE2_LOWER_BOUND, state->surface2_lower_bound);
+       MMIO_W(SURFACE2_UPPER_BOUND, state->surface2_upper_bound);
+       MMIO_W(SURFACE3_INFO, state->surface3_info);
+       MMIO_W(SURFACE3_LOWER_BOUND, state->surface3_lower_bound);
+       MMIO_W(SURFACE3_UPPER_BOUND, state->surface3_upper_bound);
+       MMIO_W(SURFACE4_INFO, state->surface4_info);
+       MMIO_W(SURFACE4_LOWER_BOUND, state->surface4_lower_bound);
+       MMIO_W(SURFACE4_UPPER_BOUND, state->surface4_upper_bound);
+       MMIO_W(SURFACE5_INFO, state->surface5_info);
+       MMIO_W(SURFACE5_LOWER_BOUND, state->surface5_lower_bound);
+       MMIO_W(SURFACE5_UPPER_BOUND, state->surface5_upper_bound);
+       MMIO_W(SURFACE6_INFO, state->surface6_info);
+       MMIO_W(SURFACE6_LOWER_BOUND, state->surface6_lower_bound);
+       MMIO_W(SURFACE6_UPPER_BOUND, state->surface6_upper_bound);
+       MMIO_W(SURFACE7_INFO, state->surface7_info);
+       MMIO_W(SURFACE7_LOWER_BOUND, state->surface7_lower_bound);
+       MMIO_W(SURFACE7_UPPER_BOUND, state->surface7_upper_bound);
+       MMIO_W(CRTC_H_TOTAL_DISP, state->crtc_h_total_disp);
+       MMIO_W(CRTC_H_SYNC_STRT_WID, state->crtc_h_sync_strt_wid);
+       MMIO_W(CRTC_V_TOTAL_DISP, state->crtc_v_total_disp);
+       MMIO_W(CRTC_V_SYNC_STRT_WID, state->crtc_v_sync_strt_wid);
+       MMIO_W(FP_H_SYNC_STRT_WID, state->fp_h_sync_strt_wid);
+       MMIO_W(FP_V_SYNC_STRT_WID, state->fp_v_sync_strt_wid);
+       MMIO_W(FP_CRTC_H_TOTAL_DISP, state->fp_crtc_h_total_disp);
+       MMIO_W(FP_CRTC_V_TOTAL_DISP, state->fp_crtc_v_total_disp);
+       MMIO_W(CRTC_TILE_X0_Y0, state->crtc_tile_x0_y0);
+       MMIO_W(CRTC_OFFSET_CNTL, state->crtc_offset_cntl);
+       MMIO_W(CRTC_OFFSET, state->crtc_offset);
+       MMIO_W(CRTC_PITCH, state->crtc_pitch);
+       radeon_pll1_restore(dev_priv, state);
+       MMIO_W(CRTC_MORE_CNTL, state->crtc_more_cntl);
+       MMIO_W(CRTC_GEN_CNTL, state->crtc_gen_cntl);
+       MMIO_W(CRTC_EXT_CNTL, state->crtc_ext_cntl);
+}
+
+/**
+ * radeon_pll1_restore - restore PLL1 state
+ * @dev_priv: radeon private structure
+ * @state: PLL1 state to restore
+ */
+static void radeon_pll1_restore(struct drm_radeon_private *dev_priv,
+                               struct radeon_state *state)
+{
+       uint32_t tmp;
+
+       /* switch to gpu clock while programing new clock */
+       MMIO_W(CLOCK_CNTL_INDEX, state->clock_cntl_index);
+       tmp = state->vclk_ecp_cntl;
+       tmp = REG_S(VCLK_ECP_CNTL, VCLK_SRC_SEL, VCLK_SRC_SEL__CPUCLK);
+       PPLL_W(VCLK_ECP_CNTL, tmp);
+       /* reset PLL and update atomicly */
+       state->ppll_cntl |= PPLL_CNTL__PPLL_ATOMIC_UPDATE_EN |
+               PPLL_CNTL__PPLL_ATOMIC_UPDATE_SYNC; 
+
+       PPLL_W(PPLL_CNTL, state->ppll_cntl | PPLL_CNTL__PPLL_RESET);
+       PPLL_W(PPLL_REF_DIV, state->ppll_ref_div);
+       PPLL_W(PPLL_DIV_0, state->ppll_div_0);
+       PPLL_W(PPLL_DIV_1, state->ppll_div_1);
+       PPLL_W(PPLL_DIV_2, state->ppll_div_2);
+       PPLL_W(PPLL_DIV_3, state->ppll_div_3);
+       PPLL_W(HTOTAL_CNTL, state->htotal_cntl);
+
+       /* update */
+       PPLL_W(PPLL_REF_DIV, state->ppll_ref_div |
+                       PPLL_REF_DIV__PPLL_ATOMIC_UPDATE_W);
+       for (tmp = 0; tmp < 100; tmp++) {
+               if (!(PPLL_REF_DIV__PPLL_ATOMIC_UPDATE_R &
+                                       PPLL_R(PPLL_REF_DIV))) {
+                     break;
+               }
+               DRM_UDELAY(10);
+       }
+       state->ppll_cntl &= ~PPLL_CNTL__PPLL_RESET;
+       PPLL_W(PPLL_CNTL, state->ppll_cntl);
+       PPLL_W(VCLK_ECP_CNTL, state->vclk_ecp_cntl);
+}
+
+/**
+ * radeon_ms_crtc1_save - save CRTC state
+ * @dev_priv: radeon private structure
+ * @state: state where saving current CRTC state
+ */
+void radeon_ms_crtc1_save(struct drm_device *dev, struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       state->surface_cntl = MMIO_R(SURFACE_CNTL);
+       state->surface0_info = MMIO_R(SURFACE0_INFO);
+       state->surface0_lower_bound = MMIO_R(SURFACE0_LOWER_BOUND);
+       state->surface0_upper_bound = MMIO_R(SURFACE0_UPPER_BOUND);
+       state->surface1_info = MMIO_R(SURFACE1_INFO);
+       state->surface1_lower_bound = MMIO_R(SURFACE1_LOWER_BOUND);
+       state->surface1_upper_bound = MMIO_R(SURFACE1_UPPER_BOUND);
+       state->surface2_info = MMIO_R(SURFACE2_INFO);
+       state->surface2_lower_bound = MMIO_R(SURFACE2_LOWER_BOUND);
+       state->surface2_upper_bound = MMIO_R(SURFACE2_UPPER_BOUND);
+       state->surface3_info = MMIO_R(SURFACE3_INFO);
+       state->surface3_lower_bound = MMIO_R(SURFACE3_LOWER_BOUND);
+       state->surface3_upper_bound = MMIO_R(SURFACE3_UPPER_BOUND);
+       state->surface4_info = MMIO_R(SURFACE4_INFO);
+       state->surface4_lower_bound = MMIO_R(SURFACE4_LOWER_BOUND);
+       state->surface4_upper_bound = MMIO_R(SURFACE4_UPPER_BOUND);
+       state->surface5_info = MMIO_R(SURFACE5_INFO);
+       state->surface5_lower_bound = MMIO_R(SURFACE5_LOWER_BOUND);
+       state->surface5_upper_bound = MMIO_R(SURFACE5_UPPER_BOUND);
+       state->surface6_info = MMIO_R(SURFACE6_INFO);
+       state->surface6_lower_bound = MMIO_R(SURFACE6_LOWER_BOUND);
+       state->surface6_upper_bound = MMIO_R(SURFACE6_UPPER_BOUND);
+       state->surface7_info = MMIO_R(SURFACE7_INFO);
+       state->surface7_lower_bound = MMIO_R(SURFACE7_LOWER_BOUND);
+       state->surface7_upper_bound = MMIO_R(SURFACE7_UPPER_BOUND);
+       state->crtc_gen_cntl = MMIO_R(CRTC_GEN_CNTL);
+       state->crtc_ext_cntl = MMIO_R(CRTC_EXT_CNTL);
+       state->crtc_h_total_disp = MMIO_R(CRTC_H_TOTAL_DISP);
+       state->crtc_h_sync_strt_wid = MMIO_R(CRTC_H_SYNC_STRT_WID);
+       state->crtc_v_total_disp = MMIO_R(CRTC_V_TOTAL_DISP);
+       state->crtc_v_sync_strt_wid = MMIO_R(CRTC_V_SYNC_STRT_WID);
+       state->fp_h_sync_strt_wid = MMIO_R(FP_H_SYNC_STRT_WID);
+       state->fp_v_sync_strt_wid = MMIO_R(FP_V_SYNC_STRT_WID);
+       state->fp_crtc_h_total_disp = MMIO_R(FP_CRTC_H_TOTAL_DISP);
+       state->fp_crtc_v_total_disp = MMIO_R(FP_CRTC_V_TOTAL_DISP);
+       state->crtc_offset = MMIO_R(CRTC_OFFSET);
+       state->crtc_offset_cntl = MMIO_R(CRTC_OFFSET_CNTL);
+       state->crtc_pitch = MMIO_R(CRTC_PITCH);
+       state->crtc_more_cntl = MMIO_R(CRTC_MORE_CNTL);
+       state->crtc_tile_x0_y0 =  MMIO_R(CRTC_TILE_X0_Y0);
+       radeon_pll1_save(dev_priv,state);
+}
+
+/**
+ * radeon_pll1_save - save PLL1 state
+ * @dev_priv: radeon private structure
+ * @state: state where saving current PLL1 state
+ */
+static void radeon_pll1_save(struct drm_radeon_private *dev_priv,
+                            struct radeon_state *state)
+{
+       state->clock_cntl_index = MMIO_R(CLOCK_CNTL_INDEX);
+       state->ppll_cntl = PPLL_R(PPLL_CNTL);
+       state->ppll_ref_div = PPLL_R(PPLL_REF_DIV);
+       state->ppll_div_0 = PPLL_R(PPLL_DIV_0);
+       state->ppll_div_1 = PPLL_R(PPLL_DIV_1);
+       state->ppll_div_2 = PPLL_R(PPLL_DIV_2);
+       state->ppll_div_3 = PPLL_R(PPLL_DIV_3);
+       state->vclk_ecp_cntl = PPLL_R(VCLK_ECP_CNTL);
+       state->htotal_cntl = PPLL_R(HTOTAL_CNTL);
+}
+
+static void radeon_ms_crtc1_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct drm_radeon_private *dev_priv = crtc->dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+
+       state->crtc_gen_cntl &= ~CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B;
+       state->crtc_ext_cntl &= ~CRTC_EXT_CNTL__CRTC_DISPLAY_DIS;
+       state->crtc_ext_cntl &= ~CRTC_EXT_CNTL__CRTC_HSYNC_DIS;
+       state->crtc_ext_cntl &= ~CRTC_EXT_CNTL__CRTC_VSYNC_DIS;
+       switch(mode) {
+       case DPMSModeOn:
+               break;
+       case DPMSModeStandby:
+               state->crtc_ext_cntl |=
+                       CRTC_EXT_CNTL__CRTC_DISPLAY_DIS |
+                       CRTC_EXT_CNTL__CRTC_HSYNC_DIS;
+               break;
+       case DPMSModeSuspend:
+               state->crtc_ext_cntl |=
+                       CRTC_EXT_CNTL__CRTC_DISPLAY_DIS |
+                       CRTC_EXT_CNTL__CRTC_VSYNC_DIS;
+               break;
+       case DPMSModeOff:
+               state->crtc_ext_cntl |=
+                       CRTC_EXT_CNTL__CRTC_DISPLAY_DIS |
+                       CRTC_EXT_CNTL__CRTC_HSYNC_DIS |
+                       CRTC_EXT_CNTL__CRTC_VSYNC_DIS;
+               state->crtc_gen_cntl |=
+                       CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B;
+               break;
+       }
+       MMIO_W(CRTC_GEN_CNTL, state->crtc_gen_cntl);
+       MMIO_W(CRTC_EXT_CNTL, state->crtc_ext_cntl);
+
+       dev_priv->crtc1_dpms = mode;
+       /* FIXME: once adding crtc2 remove this */
+       dev_priv->crtc2_dpms = mode;
+       radeon_ms_gpu_dpms(crtc->dev);
+
+       if (mode != DPMSModeOff) {
+               radeon_ms_crtc_load_lut(crtc);
+       }
+}
+
+static bool radeon_ms_crtc_mode_fixup(struct drm_crtc *crtc,
+                                     struct drm_display_mode *mode,
+                                     struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void radeon_ms_crtc_mode_prepare(struct drm_crtc *crtc)
+{
+       crtc->funcs->dpms(crtc, DPMSModeOff);
+}
+
+/* compute PLL registers values for requested video mode */
+static int radeon_pll1_constraint(struct drm_device *dev,
+                                 int clock, int rdiv,
+                                  int fdiv, int pdiv,
+                                  int rfrq, int pfrq)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       int dfrq;
+
+       if (rdiv < 2 || fdiv < 4) {
+               return 0;
+       }
+       dfrq = rfrq / rdiv;
+       if (dfrq < 2000 || dfrq > 3300) {
+               return 0;
+       }
+       if (pfrq < dev_priv->properties.pll_min_pll_freq ||
+           pfrq > dev_priv->properties.pll_max_pll_freq) {
+               return 0;
+       }
+       return 1;
+}
+
+static void radeon_pll1_compute(struct drm_crtc *crtc,
+                               struct drm_display_mode *mode)
+{
+       struct {
+               int divider;
+               int divider_id;
+       } *post_div, post_divs[] = {
+               /* From RAGE 128 VR/RAGE 128 GL Register
+                * Reference Manual (Technical Reference
+                * Manual P/N RRG-G04100-C Rev. 0.04), page
+                * 3-17 (PLL_DIV_[3:0]).
+                */
+               {  1, 0 },              /* VCLK_SRC                 */
+               {  2, 1 },              /* VCLK_SRC/2               */
+               {  4, 2 },              /* VCLK_SRC/4               */
+               {  8, 3 },              /* VCLK_SRC/8               */
+               {  3, 4 },              /* VCLK_SRC/3               */
+               { 16, 5 },              /* VCLK_SRC/16              */
+               {  6, 6 },              /* VCLK_SRC/6               */
+               { 12, 7 },              /* VCLK_SRC/12              */
+               {  0, 0 }
+       };
+       struct drm_radeon_private *dev_priv = crtc->dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+       int clock = mode->clock;
+       int rfrq = dev_priv->properties.pll_reference_freq;
+       int pdiv = 1;
+       int pdiv_id = 0;
+       int rdiv_best = 2;
+       int fdiv_best = 4;
+       int tfrq_best = 0;
+       int pfrq_best = 0;
+       int diff_cpfrq_best = 350000;
+       int vco_freq;
+       int vco_gain;
+       int rdiv = 0;
+       int fdiv = 0;
+       int tfrq = 35000;
+       int pfrq = 35000;
+       int diff_cpfrq = 350000;
+
+       /* clamp frequency into pll [min; max] frequency range */
+       if (clock > dev_priv->properties.pll_max_pll_freq) {
+               clock = dev_priv->properties.pll_max_pll_freq;
+       }
+       if ((clock * 12) < dev_priv->properties.pll_min_pll_freq) {
+               clock = dev_priv->properties.pll_min_pll_freq / 12;
+       }
+
+       /* maximize pll_ref_div while staying in boundary and minimizing
+        * the difference btw target frequency and programmed frequency */
+       for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
+               if (post_div->divider == 0) {
+                       break;
+               }
+               tfrq = clock * post_div->divider;
+               for (fdiv = 1023; fdiv >= 4; fdiv--) {
+                       rdiv = (fdiv * rfrq) / tfrq;
+                       if (radeon_pll1_constraint(crtc->dev, clock, rdiv,
+                                                  fdiv, pdiv, rfrq, tfrq)) {
+                               pfrq = (fdiv * rfrq) / rdiv;
+                               diff_cpfrq = pfrq - tfrq;
+                               if ((diff_cpfrq >= 0 &&
+                                    diff_cpfrq < diff_cpfrq_best) ||
+                                   (diff_cpfrq == diff_cpfrq_best &&
+                                    rdiv > rdiv_best)) {
+                                       rdiv_best = rdiv;
+                                       fdiv_best = fdiv;
+                                       tfrq_best = tfrq;
+                                       pfrq_best = pfrq;
+                                       pdiv = post_div->divider;
+                                       pdiv_id = post_div->divider_id;
+                                       diff_cpfrq_best = diff_cpfrq;
+                               }
+                       }
+               }
+       }
+       state->ppll_ref_div =
+               REG_S(PPLL_REF_DIV, PPLL_REF_DIV, rdiv_best) |
+               REG_S(PPLL_REF_DIV, PPLL_REF_DIV_ACC, rdiv_best);
+       state->ppll_div_0 = REG_S(PPLL_DIV_0, PPLL_FB0_DIV, fdiv_best) |
+               REG_S(PPLL_DIV_0, PPLL_POST0_DIV, pdiv_id);
+
+       vco_freq = (fdiv_best * rfrq) / rdiv_best;
+       /* This is horribly crude: the VCO frequency range is divided into
+        * 3 parts, each part having a fixed PLL gain value.
+        */
+        if (vco_freq >= 300000) {
+               /* [300..max] MHz : 7 */
+               vco_gain = 7;
+       } else if (vco_freq >= 180000) {
+               /* [180..300) MHz : 4 */
+               vco_gain = 4;
+       } else {
+               /* [0..180) MHz : 1 */
+               vco_gain = 1;
+       }
+       state->ppll_cntl |= REG_S(PPLL_CNTL, PPLL_PVG, vco_gain);
+       state->vclk_ecp_cntl |= REG_S(VCLK_ECP_CNTL, VCLK_SRC_SEL,
+                       VCLK_SRC_SEL__PPLLCLK);
+       state->htotal_cntl = 0;
+       DRM_INFO("rdiv: %d\n", rdiv_best);
+       DRM_INFO("fdiv: %d\n", fdiv_best);
+       DRM_INFO("pdiv: %d\n", pdiv);
+       DRM_INFO("pdiv: %d\n", pdiv_id);
+       DRM_INFO("tfrq: %d\n", tfrq_best);
+       DRM_INFO("pfrq: %d\n", pfrq_best);
+       DRM_INFO("PPLL_REF_DIV:  0x%08X\n", state->ppll_ref_div);
+       DRM_INFO("PPLL_DIV_0:    0x%08X\n", state->ppll_div_0);
+       DRM_INFO("PPLL_CNTL:     0x%08X\n", state->ppll_cntl);
+       DRM_INFO("VCLK_ECP_CNTL: 0x%08X\n", state->vclk_ecp_cntl);
+}
+
+static void radeon_ms_crtc1_mode_set(struct drm_crtc *crtc,
+                                    struct drm_display_mode *mode,
+                                    struct drm_display_mode *adjusted_mode,
+                                    int x, int y)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+       int format, hsync_wid, vsync_wid, pitch;
+
+       DRM_INFO("[radeon_ms] set modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x\n",
+                 mode->mode_id, mode->name, mode->vrefresh, mode->clock,
+                 mode->hdisplay, mode->hsync_start,
+                 mode->hsync_end, mode->htotal,
+                 mode->vdisplay, mode->vsync_start,
+                 mode->vsync_end, mode->vtotal, mode->type);
+       DRM_INFO("[radeon_ms] set modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x (adjusted)\n",
+                 adjusted_mode->mode_id, adjusted_mode->name, adjusted_mode->vrefresh, adjusted_mode->clock,
+                 adjusted_mode->hdisplay, adjusted_mode->hsync_start,
+                 adjusted_mode->hsync_end, adjusted_mode->htotal,
+                 adjusted_mode->vdisplay, adjusted_mode->vsync_start,
+                 adjusted_mode->vsync_end, adjusted_mode->vtotal, adjusted_mode->type);
+
+       /* only support RGB555,RGB565,ARGB8888 should satisfy all users */
+       switch (crtc->fb->bits_per_pixel) {
+       case 16:
+               if (crtc->fb->depth == 15) {
+                       format = 3;
+               } else {
+                       format = 4;
+               }
+               break;
+       case 32:
+               format = 6;
+               break;
+       default:
+               DRM_ERROR("Unknown color depth\n");
+               return;
+       }
+       radeon_pll1_compute(crtc, adjusted_mode);
+
+       state->crtc_offset = REG_S(CRTC_OFFSET, CRTC_OFFSET, crtc->fb->bo->offset);
+       state->crtc_gen_cntl = CRTC_GEN_CNTL__CRTC_EXT_DISP_EN |
+               CRTC_GEN_CNTL__CRTC_EN |
+               REG_S(CRTC_GEN_CNTL, CRTC_PIX_WIDTH, format);
+       if (adjusted_mode->flags & V_DBLSCAN) {
+               state->crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_DBL_SCAN_EN;
+       }
+       if (adjusted_mode->flags & V_CSYNC) {
+               state->crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_C_SYNC_EN;
+       }
+       if (adjusted_mode->flags & V_INTERLACE) {
+               state->crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_INTERLACE_EN;
+       }
+       state->crtc_more_cntl = 0;
+       state->crtc_h_total_disp =
+               REG_S(CRTC_H_TOTAL_DISP,
+                               CRTC_H_TOTAL,
+                               (adjusted_mode->crtc_htotal/8) - 1) |
+               REG_S(CRTC_H_TOTAL_DISP,
+                               CRTC_H_DISP,
+                               (adjusted_mode->crtc_hdisplay/8) - 1);
+       hsync_wid = (adjusted_mode->crtc_hsync_end -
+                    adjusted_mode->crtc_hsync_start) / 8;
+       if (!hsync_wid) {
+               hsync_wid = 1;
+       }
+       if (hsync_wid > 0x3f) {
+               hsync_wid = 0x3f;
+       }
+       state->crtc_h_sync_strt_wid =
+               REG_S(CRTC_H_SYNC_STRT_WID,
+                               CRTC_H_SYNC_WID, hsync_wid) |
+               REG_S(CRTC_H_SYNC_STRT_WID,
+                               CRTC_H_SYNC_STRT_PIX,
+                               adjusted_mode->crtc_hsync_start) |
+               REG_S(CRTC_H_SYNC_STRT_WID,
+                               CRTC_H_SYNC_STRT_CHAR,
+                               adjusted_mode->crtc_hsync_start/8);
+       if (adjusted_mode->flags & V_NHSYNC) {
+               state->crtc_h_sync_strt_wid |=
+                       CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_POL;
+       }
+
+       state->crtc_v_total_disp =
+               REG_S(CRTC_V_TOTAL_DISP, CRTC_V_TOTAL,
+                               adjusted_mode->crtc_vtotal - 1) |
+               REG_S(CRTC_V_TOTAL_DISP, CRTC_V_DISP,
+                               adjusted_mode->crtc_vdisplay - 1);
+       vsync_wid = adjusted_mode->crtc_vsync_end -
+                   adjusted_mode->crtc_vsync_start;
+       if (!vsync_wid) {
+               vsync_wid = 1;
+       }
+       if (vsync_wid > 0x1f) {
+               vsync_wid = 0x1f;
+       }
+       state->crtc_v_sync_strt_wid =
+               REG_S(CRTC_V_SYNC_STRT_WID,
+                               CRTC_V_SYNC_WID,
+                               vsync_wid) |
+               REG_S(CRTC_V_SYNC_STRT_WID,
+                               CRTC_V_SYNC_STRT,
+                               adjusted_mode->crtc_vsync_start);
+       if (adjusted_mode->flags & V_NVSYNC) {
+               state->crtc_v_sync_strt_wid |=
+                       CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_POL;
+       }
+
+       pitch = (crtc->fb->width * crtc->fb->bits_per_pixel +
+                ((crtc->fb->bits_per_pixel * 8)- 1)) /
+               (crtc->fb->bits_per_pixel * 8);
+       state->crtc_pitch = REG_S(CRTC_PITCH, CRTC_PITCH, pitch) |
+               REG_S(CRTC_PITCH, CRTC_PITCH_RIGHT, pitch);
+
+       state->fp_h_sync_strt_wid = state->crtc_h_sync_strt_wid;
+       state->fp_v_sync_strt_wid = state->crtc_v_sync_strt_wid;
+       state->fp_crtc_h_total_disp = state->crtc_h_total_disp;
+       state->fp_crtc_v_total_disp = state->crtc_v_total_disp;
+
+       radeon_ms_crtc1_restore(dev, state);
+}
+
+static void radeon_ms_crtc_mode_commit(struct drm_crtc *crtc)
+{
+       crtc->funcs->dpms(crtc, DPMSModeOn);
+}
+
+static void radeon_ms_crtc_gamma_set(struct drm_crtc *crtc, u16 r,
+                                    u16 g, u16 b, int regno)
+{
+       struct drm_radeon_private *dev_priv = crtc->dev->dev_private;
+       struct radeon_ms_crtc *radeon_ms_crtc = crtc->driver_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+       uint32_t color;
+
+       switch(radeon_ms_crtc->crtc) {
+       case 1:
+               state->dac_cntl2 &= ~DAC_CNTL2__PALETTE_ACCESS_CNTL;
+               break;
+       case 2:
+               state->dac_cntl2 |= DAC_CNTL2__PALETTE_ACCESS_CNTL;
+               break;
+       }
+       MMIO_W(DAC_CNTL2, state->dac_cntl2);
+       if (crtc->fb->bits_per_pixel == 16 && crtc->fb->depth == 16) {
+               if (regno >= 64) {
+                       return;
+               }
+               MMIO_W(PALETTE_INDEX,
+                               REG_S(PALETTE_INDEX, PALETTE_W_INDEX,
+                                       regno * 4));
+               color = 0;
+               color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) |
+                       REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) |
+                       REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8);
+               MMIO_W(PALETTE_DATA, color);
+               MMIO_W(PALETTE_INDEX,
+                      REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno * 4));
+               color = 0;
+               color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R, r >> 6) |
+                       REG_S(PALETTE_30_DATA, PALETTE_DATA_G, g >> 6) |
+                       REG_S(PALETTE_30_DATA, PALETTE_DATA_B, b >> 6);
+               MMIO_W(PALETTE_30_DATA, color);
+               radeon_ms_crtc->lut_r[regno * 4] = r;
+               radeon_ms_crtc->lut_g[regno * 4] = g;
+               radeon_ms_crtc->lut_b[regno * 4] = b;
+               if (regno < 32) {
+                       MMIO_W(PALETTE_INDEX,
+                              REG_S(PALETTE_INDEX, PALETTE_W_INDEX,
+                                      regno * 8));
+                       color = 0;
+                       color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) |
+                               REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) |
+                               REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8);
+                       MMIO_W(PALETTE_DATA, color);
+                       MMIO_W(PALETTE_INDEX,
+                              REG_S(PALETTE_INDEX, PALETTE_W_INDEX,
+                                     regno * 8));
+                       color = 0;
+                       color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R,r >> 6) |
+                               REG_S(PALETTE_30_DATA, PALETTE_DATA_G,g >> 6) |
+                               REG_S(PALETTE_30_DATA, PALETTE_DATA_B,b >> 6);
+                       MMIO_W(PALETTE_30_DATA, color);
+                       radeon_ms_crtc->lut_r[regno * 8] = r;
+                       radeon_ms_crtc->lut_g[regno * 8] = g;
+                       radeon_ms_crtc->lut_b[regno * 8] = b;
+               }
+       } else {
+               if (regno >= 256) {
+                       return;
+               }
+               radeon_ms_crtc->lut_r[regno] = r;
+               radeon_ms_crtc->lut_g[regno] = g;
+               radeon_ms_crtc->lut_b[regno] = b;
+               MMIO_W(PALETTE_INDEX,
+                      REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno));
+               color = 0;
+               color = REG_S(PALETTE_DATA, PALETTE_DATA_R, r >> 8) |
+                       REG_S(PALETTE_DATA, PALETTE_DATA_G, g >> 8) |
+                       REG_S(PALETTE_DATA, PALETTE_DATA_B, b >> 8);
+               MMIO_W(PALETTE_DATA, color);
+               MMIO_W(PALETTE_INDEX,
+                               REG_S(PALETTE_INDEX, PALETTE_W_INDEX, regno));
+               color = 0;
+               color = REG_S(PALETTE_30_DATA, PALETTE_DATA_R, r >> 6) |
+                       REG_S(PALETTE_30_DATA, PALETTE_DATA_G, g >> 6) |
+                       REG_S(PALETTE_30_DATA, PALETTE_DATA_B, b >> 6);
+       }
+}
+
+static void radeon_ms_crtc_load_lut(struct drm_crtc *crtc)
+{
+       struct radeon_ms_crtc *radeon_ms_crtc = crtc->driver_private;
+       int i;
+
+       if (!crtc->enabled)
+               return;
+
+       for (i = 0; i < 256; i++) {
+               radeon_ms_crtc_gamma_set(crtc,
+                               radeon_ms_crtc->lut_r[i],
+                               radeon_ms_crtc->lut_g[i],
+                               radeon_ms_crtc->lut_b[i],
+                               i);
+       }
+}
+
+static bool radeon_ms_crtc_lock(struct drm_crtc *crtc)
+{
+    return true;
+}
+
+static void radeon_ms_crtc_unlock(struct drm_crtc *crtc)
+{
+}
+
+static const struct drm_crtc_funcs radeon_ms_crtc1_funcs= {
+       .dpms = radeon_ms_crtc1_dpms,
+       .save = NULL, /* XXX */
+       .restore = NULL, /* XXX */
+       .lock = radeon_ms_crtc_lock,
+       .unlock = radeon_ms_crtc_unlock,
+       .prepare = radeon_ms_crtc_mode_prepare,
+       .commit = radeon_ms_crtc_mode_commit,
+       .mode_fixup = radeon_ms_crtc_mode_fixup,
+       .mode_set = radeon_ms_crtc1_mode_set,
+       .gamma_set = radeon_ms_crtc_gamma_set,
+       .cleanup = NULL, /* XXX */
+};
+
+int radeon_ms_crtc_create(struct drm_device *dev, int crtc)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct drm_crtc *drm_crtc;
+       struct radeon_ms_crtc *radeon_ms_crtc;
+       int i;
+
+       switch (crtc) {
+       case 1:
+               radeon_ms_crtc1_init(dev_priv, &dev_priv->driver_state);
+               drm_crtc = drm_crtc_create(dev, &radeon_ms_crtc1_funcs);
+               break;
+       case 2:
+       default:
+               return -EINVAL;
+       }
+       if (drm_crtc == NULL) {
+               return -ENOMEM;
+       }
+
+       radeon_ms_crtc = drm_alloc(sizeof(struct radeon_ms_crtc), DRM_MEM_DRIVER);
+       if (radeon_ms_crtc == NULL) {
+               kfree(drm_crtc);
+               return -ENOMEM;
+       }
+
+       radeon_ms_crtc->crtc = crtc;
+       for (i = 0; i < 256; i++) {
+               radeon_ms_crtc->lut_r[i] = i << 8;
+               radeon_ms_crtc->lut_g[i] = i << 8;
+               radeon_ms_crtc->lut_b[i] = i << 8;
+       }
+       drm_crtc->driver_private = radeon_ms_crtc;
+       return 0;
+}
diff --git a/shared-core/radeon_ms_dac.c b/shared-core/radeon_ms_dac.c
new file mode 100644 (file)
index 0000000..e631294
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * Copyright 2007 Alex Deucher
+ * Copyright 2007 Dave Airlie
+ * 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.
+ */
+#include "radeon_ms.h"
+
+int radeon_ms_dac1_initialize(struct radeon_ms_output *output)
+{
+       struct drm_radeon_private *dev_priv = output->dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+
+       state->dac_cntl =
+               REG_S(DAC_CNTL, DAC_RANGE_CNTL, DAC_RANGE_CNTL__PS2) |
+               DAC_CNTL__DAC_8BIT_EN |
+               DAC_CNTL__DAC_VGA_ADR_EN |
+               DAC_CNTL__DAC_PDWN |
+               REG_S(DAC_CNTL, DAC, 0xff);
+       state->dac_ext_cntl = 0;
+       state->dac_macro_cntl =
+               DAC_MACRO_CNTL__DAC_PDWN_R |
+               DAC_MACRO_CNTL__DAC_PDWN_G |
+               DAC_MACRO_CNTL__DAC_PDWN_B |
+               REG_S(DAC_MACRO_CNTL, DAC_WHITE_CNTL, 7) |
+               REG_S(DAC_MACRO_CNTL, DAC_BG_ADJ, 7);
+       state->dac_embedded_sync_cntl =
+               DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_VSYNC_EN_Y_G;
+       state->dac_broad_pulse = 0;
+       state->dac_skew_clks = 0;
+       state->dac_incr = 0;
+       state->dac_neg_sync_level = 0;
+       state->dac_pos_sync_level = 0;
+       state->dac_blank_level = 0;
+       state->dac_sync_equalization = 0;
+       state->disp_output_cntl = 0;
+       radeon_ms_dac1_restore(output, state);
+       return 0;
+}
+
+enum drm_output_status radeon_ms_dac1_detect(struct radeon_ms_output *output)
+{
+       return output_status_unknown;
+}
+
+void radeon_ms_dac1_dpms(struct radeon_ms_output *output, int mode)
+{
+       struct drm_radeon_private *dev_priv = output->dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+       uint32_t dac_cntl;
+       uint32_t dac_macro_cntl;
+
+       dac_cntl = DAC_CNTL__DAC_PDWN;
+       dac_macro_cntl = DAC_MACRO_CNTL__DAC_PDWN_R |
+               DAC_MACRO_CNTL__DAC_PDWN_G |
+               DAC_MACRO_CNTL__DAC_PDWN_B;
+       switch(mode) {
+       case DPMSModeOn:
+               state->dac_cntl &= ~dac_cntl;
+               state->dac_macro_cntl &= ~dac_macro_cntl;
+               break;
+       case DPMSModeStandby:
+       case DPMSModeSuspend:
+       case DPMSModeOff:
+               state->dac_cntl |= dac_cntl;
+               state->dac_macro_cntl |= dac_macro_cntl;
+               break;
+       default:
+               /* error */
+               break;
+       }
+       MMIO_W(DAC_CNTL, state->dac_cntl);
+       MMIO_W(DAC_MACRO_CNTL, state->dac_macro_cntl);
+}
+
+int radeon_ms_dac1_get_modes(struct radeon_ms_output *output)
+{
+       return 0;
+}
+
+bool radeon_ms_dac1_mode_fixup(struct radeon_ms_output *output,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+int radeon_ms_dac1_mode_set(struct radeon_ms_output *output,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       struct drm_radeon_private *dev_priv = output->dev->dev_private;
+       struct radeon_ms_connector *connector = output->connector;
+       struct radeon_state *state = &dev_priv->driver_state;
+       uint32_t v = 0;
+
+       if (connector == NULL) {
+               /* output not associated with a connector */
+               return -EINVAL;
+       }
+       state->disp_output_cntl &= ~DISP_OUTPUT_CNTL__DISP_DAC_SOURCE__MASK;
+       state->dac_cntl2 &= ~DAC_CNTL2__DAC_CLK_SEL;
+       switch (connector->crtc) {
+       case 1:
+               v =  DISP_DAC_SOURCE__PRIMARYCRTC;
+               break;
+       case 2:
+               v =  DISP_DAC_SOURCE__SECONDARYCRTC;
+               state->dac_cntl2 |= DAC_CNTL2__DAC_CLK_SEL;
+               break;
+       }
+       state->disp_output_cntl |= REG_S(DISP_OUTPUT_CNTL, DISP_DAC_SOURCE, v);
+       MMIO_W(DISP_OUTPUT_CNTL, state->disp_output_cntl);
+       MMIO_W(DAC_CNTL2, state->dac_cntl2);
+       return 0;
+}
+
+void radeon_ms_dac1_restore(struct radeon_ms_output *output,
+               struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = output->dev->dev_private;
+
+       MMIO_W(DAC_CNTL, state->dac_cntl);
+       MMIO_W(DAC_EXT_CNTL, state->dac_ext_cntl);
+       MMIO_W(DAC_MACRO_CNTL, state->dac_macro_cntl);
+       MMIO_W(DAC_EMBEDDED_SYNC_CNTL, state->dac_embedded_sync_cntl);
+       MMIO_W(DAC_BROAD_PULSE, state->dac_broad_pulse);
+       MMIO_W(DAC_SKEW_CLKS, state->dac_skew_clks);
+       MMIO_W(DAC_INCR, state->dac_incr);
+       MMIO_W(DAC_NEG_SYNC_LEVEL, state->dac_neg_sync_level);
+       MMIO_W(DAC_POS_SYNC_LEVEL, state->dac_pos_sync_level);
+       MMIO_W(DAC_BLANK_LEVEL, state->dac_blank_level);
+       MMIO_W(DAC_SYNC_EQUALIZATION, state->dac_sync_equalization);
+}
+
+void radeon_ms_dac1_save(struct radeon_ms_output *output,
+               struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = output->dev->dev_private;
+
+       state->dac_cntl = MMIO_R(DAC_CNTL);
+       state->dac_ext_cntl = MMIO_R(DAC_EXT_CNTL);
+       state->dac_macro_cntl = MMIO_R(DAC_MACRO_CNTL);
+       state->dac_embedded_sync_cntl = MMIO_R(DAC_EMBEDDED_SYNC_CNTL);
+       state->dac_broad_pulse = MMIO_R(DAC_BROAD_PULSE);
+       state->dac_skew_clks = MMIO_R(DAC_SKEW_CLKS);
+       state->dac_incr = MMIO_R(DAC_INCR);
+       state->dac_neg_sync_level = MMIO_R(DAC_NEG_SYNC_LEVEL);
+       state->dac_pos_sync_level = MMIO_R(DAC_POS_SYNC_LEVEL);
+       state->dac_blank_level = MMIO_R(DAC_BLANK_LEVEL);
+       state->dac_sync_equalization = MMIO_R(DAC_SYNC_EQUALIZATION);
+}
+
+int radeon_ms_dac2_initialize(struct radeon_ms_output *output)
+{
+       struct drm_radeon_private *dev_priv = output->dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+
+       state->tv_dac_cntl = TV_DAC_CNTL__BGSLEEP |
+               REG_S(TV_DAC_CNTL, STD, STD__PS2) |
+               REG_S(TV_DAC_CNTL, BGADJ, 0);
+       switch (dev_priv->family) {
+       case CHIP_R100:
+       case CHIP_R200:
+       case CHIP_RV200:
+       case CHIP_RV250:
+       case CHIP_RV280:
+       case CHIP_RS300:
+       case CHIP_R300:
+       case CHIP_R350:
+       case CHIP_R360:
+       case CHIP_RV350:
+       case CHIP_RV370:
+       case CHIP_RV380:
+       case CHIP_RS400:
+               state->tv_dac_cntl |= TV_DAC_CNTL__RDACPD |
+                       TV_DAC_CNTL__GDACPD |
+                       TV_DAC_CNTL__BDACPD |
+                       REG_S(TV_DAC_CNTL, DACADJ, 0);
+               break;
+       case CHIP_RV410:
+       case CHIP_R420:
+       case CHIP_R430:
+       case CHIP_R480:
+               state->tv_dac_cntl |= TV_DAC_CNTL__RDACPD_R4 |
+                       TV_DAC_CNTL__GDACPD_R4 |
+                       TV_DAC_CNTL__BDACPD_R4 |
+                       REG_S(TV_DAC_CNTL, DACADJ_R4, 0);
+               break;
+       }
+       state->tv_master_cntl = TV_MASTER_CNTL__TV_ASYNC_RST |
+               TV_MASTER_CNTL__CRT_ASYNC_RST |
+               TV_MASTER_CNTL__RESTART_PHASE_FIX |
+               TV_MASTER_CNTL__CRT_FIFO_CE_EN |
+               TV_MASTER_CNTL__TV_FIFO_CE_EN;
+       state->dac_cntl2 = 0;
+       state->disp_output_cntl = 0;
+       radeon_ms_dac2_restore(output, state);
+       return 0;
+}
+
+enum drm_output_status radeon_ms_dac2_detect(struct radeon_ms_output *output)
+{
+       return output_status_unknown;
+}
+
+void radeon_ms_dac2_dpms(struct radeon_ms_output *output, int mode)
+{
+       struct drm_radeon_private *dev_priv = output->dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+       uint32_t tv_dac_cntl_on, tv_dac_cntl_off;
+
+       tv_dac_cntl_off = TV_DAC_CNTL__BGSLEEP;
+       tv_dac_cntl_on = TV_DAC_CNTL__NBLANK |
+                        TV_DAC_CNTL__NHOLD;
+       switch (dev_priv->family) {
+       case CHIP_R100:
+       case CHIP_R200:
+       case CHIP_RV200:
+       case CHIP_RV250:
+       case CHIP_RV280:
+       case CHIP_RS300:
+       case CHIP_R300:
+       case CHIP_R350:
+       case CHIP_R360:
+       case CHIP_RV350:
+       case CHIP_RV370:
+       case CHIP_RV380:
+       case CHIP_RS400:
+               tv_dac_cntl_off |= TV_DAC_CNTL__RDACPD |
+                       TV_DAC_CNTL__GDACPD |
+                       TV_DAC_CNTL__BDACPD;
+               break;
+       case CHIP_RV410:
+       case CHIP_R420:
+       case CHIP_R430:
+       case CHIP_R480:
+               tv_dac_cntl_off |= TV_DAC_CNTL__RDACPD_R4 |
+                       TV_DAC_CNTL__GDACPD_R4 |
+                       TV_DAC_CNTL__BDACPD_R4;
+               break;
+       }
+       switch(mode) {
+       case DPMSModeOn:
+               state->tv_dac_cntl &= ~tv_dac_cntl_off;
+               state->tv_dac_cntl |= tv_dac_cntl_on;
+               break;
+       case DPMSModeStandby:
+       case DPMSModeSuspend:
+       case DPMSModeOff:
+               state->tv_dac_cntl &= ~tv_dac_cntl_on;
+               state->tv_dac_cntl |= tv_dac_cntl_off;
+               break;
+       default:
+               /* error */
+               break;
+       }
+       MMIO_W(TV_DAC_CNTL, state->tv_dac_cntl);
+}
+
+int radeon_ms_dac2_get_modes(struct radeon_ms_output *output)
+{
+       return 0;
+}
+
+bool radeon_ms_dac2_mode_fixup(struct radeon_ms_output *output,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+int radeon_ms_dac2_mode_set(struct radeon_ms_output *output,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       struct drm_radeon_private *dev_priv = output->dev->dev_private;
+       struct radeon_ms_connector *connector = output->connector;
+       struct radeon_state *state = &dev_priv->driver_state;
+
+       if (connector == NULL) {
+               /* output not associated with a connector */
+               return -EINVAL;
+       }
+       switch (dev_priv->family) {
+       case CHIP_R100:
+       case CHIP_R200:
+               state->disp_output_cntl &= ~DISP_OUTPUT_CNTL__DISP_TV_SOURCE;
+               switch (connector->crtc) {
+               case 1:
+                       break;
+               case 2:
+                       state->disp_output_cntl |=
+                               DISP_OUTPUT_CNTL__DISP_TV_SOURCE;
+                       break;
+               }
+               break;
+       case CHIP_RV200:
+       case CHIP_RV250:
+       case CHIP_RV280:
+       case CHIP_RS300:
+               break;
+       case CHIP_R300:
+       case CHIP_R350:
+       case CHIP_R360:
+       case CHIP_RV350:
+       case CHIP_RV370:
+       case CHIP_RV380:
+       case CHIP_RS400:
+       case CHIP_RV410:
+       case CHIP_R420:
+       case CHIP_R430:
+       case CHIP_R480:
+               state->disp_output_cntl &=
+                       ~DISP_OUTPUT_CNTL__DISP_TVDAC_SOURCE__MASK;
+               switch (connector->crtc) {
+               case 1:
+                       state->disp_output_cntl |=
+                               REG_S(DISP_OUTPUT_CNTL,
+                                               DISP_TVDAC_SOURCE,
+                                               DISP_TVDAC_SOURCE__PRIMARYCRTC);
+                               break;
+               case 2:
+                               state->disp_output_cntl |=
+                                       REG_S(DISP_OUTPUT_CNTL,
+                                                       DISP_TVDAC_SOURCE,
+                                                       DISP_TVDAC_SOURCE__SECONDARYCRTC);
+                               break;
+               }
+               break;
+       }
+       switch (dev_priv->family) {
+       case CHIP_R200:
+               break;
+       case CHIP_R100:
+       case CHIP_RV200:
+       case CHIP_RV250:
+       case CHIP_RV280:
+       case CHIP_RS300:
+       case CHIP_R300:
+       case CHIP_R350:
+       case CHIP_R360:
+       case CHIP_RV350:
+       case CHIP_RV370:
+       case CHIP_RV380:
+       case CHIP_RS400:
+       case CHIP_RV410:
+       case CHIP_R420:
+       case CHIP_R430:
+       case CHIP_R480:
+               if (connector->type != CONNECTOR_CTV &&
+                   connector->type != CONNECTOR_STV) {
+                       state->dac_cntl2 |= DAC_CNTL2__DAC2_CLK_SEL;
+               }
+       }
+       MMIO_W(DAC_CNTL2, state->dac_cntl2);
+       MMIO_W(DISP_OUTPUT_CNTL, state->disp_output_cntl);
+       return 0;
+}
+
+void radeon_ms_dac2_restore(struct radeon_ms_output *output,
+               struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = output->dev->dev_private;
+
+       MMIO_W(DAC_CNTL2, state->dac_cntl2);
+       MMIO_W(TV_DAC_CNTL, state->tv_dac_cntl);
+       MMIO_W(TV_MASTER_CNTL, state->tv_master_cntl);
+}
+
+void radeon_ms_dac2_save(struct radeon_ms_output *output,
+               struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = output->dev->dev_private;
+
+       state->dac_cntl2 = MMIO_R(DAC_CNTL2);
+       state->tv_dac_cntl = MMIO_R(TV_DAC_CNTL);
+       state->tv_master_cntl = MMIO_R(TV_MASTER_CNTL);
+}
diff --git a/shared-core/radeon_ms_drm.c b/shared-core/radeon_ms_drm.c
new file mode 100644 (file)
index 0000000..857182a
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * Copyright 2007 Alex Deucher
+ * Copyright 2007 Dave Airlie
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ */
+/*
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#include "drm_pciids.h"
+#include "radeon_ms.h"
+
+
+static uint32_t radeon_ms_mem_prios[] = {
+       DRM_BO_MEM_VRAM,
+       DRM_BO_MEM_TT,
+       DRM_BO_MEM_LOCAL,
+};
+
+static uint32_t radeon_ms_busy_prios[] = {
+       DRM_BO_MEM_TT,
+       DRM_BO_MEM_VRAM,
+       DRM_BO_MEM_LOCAL,
+};
+
+struct drm_fence_driver radeon_ms_fence_driver = {
+       .num_classes = 1,
+       .wrap_diff = (1 << 30),
+       .flush_diff = (1 << 29),
+       .sequence_mask = 0xffffffffU,
+       .lazy_capable = 1,
+       .emit = radeon_ms_fence_emit_sequence,
+       .poke_flush = radeon_ms_poke_flush,
+       .has_irq = radeon_ms_fence_has_irq,
+};
+
+struct drm_bo_driver radeon_ms_bo_driver = {
+       .mem_type_prio = radeon_ms_mem_prios,
+       .mem_busy_prio = radeon_ms_busy_prios,
+       .num_mem_type_prio = sizeof(radeon_ms_mem_prios)/sizeof(uint32_t),
+       .num_mem_busy_prio = sizeof(radeon_ms_busy_prios)/sizeof(uint32_t),
+       .create_ttm_backend_entry = radeon_ms_create_ttm_backend,
+       .fence_type = radeon_ms_fence_types,
+       .invalidate_caches = radeon_ms_invalidate_caches,
+       .init_mem_type = radeon_ms_init_mem_type,
+       .evict_flags = radeon_ms_evict_flags,
+       .move = radeon_ms_bo_move,
+       .ttm_cache_flush = radeon_ms_ttm_flush,
+};
+
+struct drm_ioctl_desc radeon_ms_ioctls[] = {
+       DRM_IOCTL_DEF(DRM_RADEON_EXECBUFFER, radeon_ms_execbuffer, DRM_AUTH),
+};
+int radeon_ms_num_ioctls = DRM_ARRAY_SIZE(radeon_ms_ioctls);
+
+int radeon_ms_driver_dma_ioctl(struct drm_device *dev, void *data,
+                              struct drm_file *file_priv)
+{
+       struct drm_device_dma *dma = dev->dma;
+       struct drm_dma *d = data;
+
+       LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+       /* Please don't send us buffers.
+        */
+       if (d->send_count != 0) {
+               DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
+                         DRM_CURRENTPID, d->send_count);
+               return -EINVAL;
+       }
+
+       /* Don't ask us buffer neither :)
+        */
+       DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
+                 DRM_CURRENTPID, d->request_count, dma->buf_count);
+       return -EINVAL;
+}
+
+void radeon_ms_driver_lastclose(struct drm_device * dev)
+{
+}
+
+int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags)
+{
+       struct drm_radeon_private *dev_priv;
+       int ret = 0;
+
+       DRM_INFO("[radeon_ms] loading\n");
+       /* allocate and clear device private structure */
+       dev_priv = drm_alloc(sizeof(struct drm_radeon_private), DRM_MEM_DRIVER);
+       if (dev_priv == NULL)
+               return -ENOMEM;
+       memset(dev_priv, 0, sizeof(struct drm_radeon_private));
+       dev->dev_private = (void *)dev_priv;
+
+       /* initialize modesetting structure (must be done here) */
+       drm_mode_config_init(dev);
+
+       /* flags correspond to chipset family */
+       dev_priv->usec_timeout = 100;
+       dev_priv->family = flags & 0xffffU;
+       dev_priv->bus_type = flags & 0xff0000U;
+       /* initialize family functions */
+       ret = radeon_ms_family_init(dev);
+       if (ret != 0) {
+               radeon_ms_driver_unload(dev);
+               return ret;
+       }
+
+       /* we don't want userspace to be able to map this so don't use
+        * drm_addmap */
+       dev_priv->mmio.offset = drm_get_resource_start(dev, 2);
+       dev_priv->mmio.size = drm_get_resource_len(dev, 2);
+       dev_priv->mmio.type = _DRM_REGISTERS;
+       dev_priv->mmio.flags = _DRM_RESTRICTED;
+       drm_core_ioremap(&dev_priv->mmio, dev); 
+       /* map vram FIXME: IGP likely don't have any of this */
+       dev_priv->vram.offset = drm_get_resource_start(dev, 0);
+       dev_priv->vram.size = drm_get_resource_len(dev, 0);
+       dev_priv->vram.type = _DRM_FRAME_BUFFER;
+       dev_priv->vram.flags = _DRM_RESTRICTED;
+       drm_core_ioremap(&dev_priv->vram, dev);
+
+       /* save radeon initial state which will be restored upon module
+        * exit */
+       radeon_ms_state_save(dev, &dev_priv->load_state);
+       dev_priv->restore_state = 1;
+       memcpy(&dev_priv->driver_state, &dev_priv->load_state,
+              sizeof(struct radeon_state));
+
+       /* initialize irq */
+       ret = radeon_ms_irq_init(dev);
+       if (ret != 0) {
+               radeon_ms_driver_unload(dev);
+               return ret;
+       }
+
+       /* init bo driver */
+       dev_priv->fence_id_last = 1;
+       dev_priv->fence_reg = SCRATCH_REG2;
+       drm_bo_driver_init(dev);
+       /* initialize vram */
+       ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, dev_priv->vram.size, 1);
+       if (ret != 0) {
+               radeon_ms_driver_unload(dev);
+               return ret;
+       }
+
+       /* initialize gpu address space (only after) VRAM initialization */
+       ret = radeon_ms_gpu_initialize(dev);
+       if (ret != 0) {
+               radeon_ms_driver_unload(dev);
+               return ret;
+       }
+       radeon_ms_gpu_restore(dev, &dev_priv->driver_state);
+
+       /* initialize ttm */
+       ret = drm_bo_init_mm(dev, DRM_BO_MEM_TT, 0,
+                            dev_priv->gpu_gart_size / RADEON_PAGE_SIZE, 1);
+       if (ret != 0) {
+               radeon_ms_driver_unload(dev);
+               return ret;
+       }
+
+       /* initialize ring buffer */
+       /* set ring size to 4Mo FIXME: should make a parameter for this */
+       dev_priv->write_back_area_size = 4 * 1024;
+       dev_priv->ring_buffer_size = 4 * 1024 * 1024;
+       ret = radeon_ms_cp_init(dev);
+       if (ret != 0) {
+               radeon_ms_driver_unload(dev);
+               return ret;
+       }
+
+       /* initialize modesetting */
+       dev->mode_config.min_width = 0;
+       dev->mode_config.min_height = 0;
+       dev->mode_config.max_width = 4096;
+       dev->mode_config.max_height = 4096;
+       dev->mode_config.fb_base = dev_priv->vram.offset;
+       ret = radeon_ms_crtc_create(dev, 1);
+       if (ret != 0) {
+               radeon_ms_driver_unload(dev);
+               return ret;
+       }
+       ret = radeon_ms_outputs_from_rom(dev);
+       if (ret < 0) {
+               radeon_ms_driver_unload(dev);
+               return ret;
+       } else if (!ret) {
+               ret = radeon_ms_outputs_from_properties(dev);
+               if (ret < 0) {
+                       radeon_ms_driver_unload(dev);
+                       return ret;
+               } else if (ret == 0) {
+                       DRM_INFO("[radeon_ms] no outputs !\n");
+               }
+       } else {
+               DRM_INFO("[radeon_ms] added %d outputs from rom.\n", ret);
+       }
+       ret = radeon_ms_connectors_from_rom(dev);
+       if (ret < 0) {
+               radeon_ms_driver_unload(dev);
+               return ret;
+       } else if (!ret) {
+               ret = radeon_ms_connectors_from_properties(dev);
+               if (ret < 0) {
+                       radeon_ms_driver_unload(dev);
+                       return ret;
+               } else if (!ret) {
+                       DRM_INFO("[radeon_ms] no connectors !\n");
+               }
+       } else {
+               DRM_INFO("[radeon_ms] added %d connectors from rom.\n", ret);
+       }
+       radeon_ms_outputs_save(dev, &dev_priv->load_state);
+       drm_initial_config(dev, false);
+
+       ret = drm_irq_install(dev);
+       if (ret != 0) {
+               radeon_ms_driver_unload(dev);
+               return ret;
+       }
+
+       DRM_INFO("[radeon_ms] successfull initialization\n");
+       return 0;
+}
+
+int radeon_ms_driver_open(struct drm_device * dev, struct drm_file *file_priv)
+{
+       return 0;
+}
+
+
+int radeon_ms_driver_unload(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       if (dev_priv == NULL) {
+               return 0;
+       }
+
+       /* cleanup modesetting */
+       drm_mode_config_cleanup(dev);
+       DRM_INFO("[radeon_ms] modesetting clean\n");
+       radeon_ms_outputs_restore(dev, &dev_priv->load_state);
+       radeon_ms_connectors_destroy(dev);
+       radeon_ms_outputs_destroy(dev);
+       
+       /* shutdown cp engine */
+       radeon_ms_cp_finish(dev);
+       DRM_INFO("[radeon_ms] cp clean\n");
+
+       drm_irq_uninstall(dev);
+       DRM_INFO("[radeon_ms] irq uninstalled\n");
+
+       DRM_INFO("[radeon_ms] unloading\n");
+       /* clean ttm memory manager */
+       mutex_lock(&dev->struct_mutex);
+       if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT, 1)) {
+               DRM_ERROR("TT memory manager not clean. Delaying takedown\n");
+       }
+       mutex_unlock(&dev->struct_mutex);
+       DRM_INFO("[radeon_ms] TT memory clean\n");
+       /* finish */
+       if (dev_priv->bus_finish) {
+               dev_priv->bus_finish(dev);
+       }
+       DRM_INFO("[radeon_ms] bus down\n");
+       /* clean vram memory manager */
+       mutex_lock(&dev->struct_mutex);
+       if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM, 1)) {
+               DRM_ERROR("VRAM memory manager not clean. Delaying takedown\n");
+       }
+       mutex_unlock(&dev->struct_mutex);
+       DRM_INFO("[radeon_ms] VRAM memory clean\n");
+       /* clean memory manager */
+       drm_bo_driver_finish(dev);
+       DRM_INFO("[radeon_ms] memory manager clean\n");
+       /* restore card state */
+       if (dev_priv->restore_state) {
+               radeon_ms_state_restore(dev, &dev_priv->load_state);
+       }
+       DRM_INFO("[radeon_ms] state restored\n");
+       if (dev_priv->mmio.handle) {
+               drm_core_ioremapfree(&dev_priv->mmio, dev);
+       }
+       if (dev_priv->vram.handle) {
+               drm_core_ioremapfree(&dev_priv->vram, dev);
+       }
+       DRM_INFO("[radeon_ms] map released\n");
+       drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
+       dev->dev_private = NULL;
+
+       DRM_INFO("[radeon_ms] that's all the folks\n");
+       return 0;
+}
+
diff --git a/shared-core/radeon_ms_drm.h b/shared-core/radeon_ms_drm.h
new file mode 100644 (file)
index 0000000..842d533
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * Copyright 2007 Dave Airlie
+ * Copyright 2007 Alex Deucher
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ */
+/*
+ * Authors:
+ *    Jérôme Glisse <glisse@freedesktop.org>
+ */
+#ifndef __RADEON_MS_DRM_H__
+#define __RADEON_MS_DRM_H__
+
+/* fence definitions */
+/* The only fence class we support */
+#define DRM_RADEON_FENCE_CLASS_ACCEL 0
+/* Fence type that guarantees read-write flush */
+#define DRM_RADEON_FENCE_TYPE_RW 2
+/* cache flushes programmed just before the fence */
+#define DRM_RADEON_FENCE_FLAG_FLUSHED 0x01000000
+
+/* radeon ms ioctl */
+#define DRM_RADEON_EXECBUFFER  0x00
+
+struct drm_radeon_execbuffer_arg {
+       uint64_t    next;
+       uint32_t    reloc_offset;
+       union {
+               struct drm_bo_op_req    req;
+               struct drm_bo_arg_rep   rep;
+       } d;
+};
+
+struct drm_radeon_execbuffer {
+       uint32_t args_count;
+       uint64_t args;
+       uint32_t cmd_size;
+       struct drm_fence_arg fence_arg;
+};
+
+#endif
diff --git a/shared-core/radeon_ms_exec.c b/shared-core/radeon_ms_exec.c
new file mode 100644 (file)
index 0000000..b2ce3cb
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ *
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#include "radeon_ms.h"
+
+static void radeon_ms_execbuffer_args_clean(struct drm_device *dev,
+                                           struct drm_buffer_object **buffers,
+                                           uint32_t args_count)
+{
+       mutex_lock(&dev->struct_mutex);
+       while (args_count--) {
+               drm_bo_usage_deref_locked(&buffers[args_count]);
+       }
+       mutex_unlock(&dev->struct_mutex);
+}
+
+static int radeon_ms_execbuffer_args(struct drm_device *dev,
+                                    struct drm_file *file_priv,
+                                    struct drm_radeon_execbuffer *execbuffer,
+                                    struct drm_buffer_object **buffers,
+                                    uint32_t *relocs)
+{
+       struct drm_radeon_execbuffer_arg arg;
+       struct drm_bo_arg_rep rep;
+       uint32_t args_count = 0;
+       uint64_t next = 0;
+       uint64_t data = execbuffer->args;
+       int ret = 0;
+
+       do {
+               if (args_count >= execbuffer->args_count) {
+                       DRM_ERROR("[radeon_ms] buffer count exceeded %d\n.",
+                                 execbuffer->args_count);
+                       ret = -EINVAL;
+                       goto out_err;
+               }
+               buffers[args_count] = NULL;
+               if (copy_from_user(&arg, (void __user *)((unsigned)data),
+                   sizeof(struct drm_radeon_execbuffer_arg))) {
+                       ret = -EFAULT;
+                       goto out_err;
+               }
+               mutex_lock(&dev->struct_mutex);
+               buffers[args_count] =
+                       drm_lookup_buffer_object(file_priv,
+                                                arg.d.req.arg_handle, 1);
+               relocs[args_count] = arg.reloc_offset;
+               mutex_unlock(&dev->struct_mutex);
+               if (arg.d.req.op != drm_bo_validate) {
+                       DRM_ERROR("[radeon_ms] buffer object operation wasn't "
+                                 "validate.\n");
+                       ret = -EINVAL;
+                       goto out_err;
+               }
+               memset(&rep, 0, sizeof(struct drm_bo_arg_rep));
+               if (args_count >= 1) {
+                       ret = drm_bo_handle_validate(file_priv,
+                                                    arg.d.req.bo_req.handle,
+                                                    arg.d.req.bo_req.fence_class,
+                                                    arg.d.req.bo_req.flags,
+                                                    arg.d.req.bo_req.mask,
+                                                    arg.d.req.bo_req.hint,
+                                                    0,
+                                                    &rep.bo_info,
+                                                    &buffers[args_count]);
+               }
+               if (ret) {
+                       DRM_ERROR("[radeon_ms] error on handle validate %d\n",
+                                 ret);
+                       rep.ret = ret;
+                       goto out_err;
+               }
+               next = arg.next;
+               arg.d.rep = rep;
+               if (copy_to_user((void __user *)((unsigned)data), &arg,
+                   sizeof(struct drm_radeon_execbuffer_arg))) {
+                       ret = -EFAULT;
+                       goto out_err;
+               }
+               data = next;
+               args_count++;
+       } while (next != 0);
+       if (args_count != execbuffer->args_count) {
+               DRM_ERROR("[radeon_ms] not enought buffer got %d waited %d\n.",
+                         args_count, execbuffer->args_count);
+               ret = -EINVAL;
+               goto out_err;
+       }
+       return 0;
+out_err:
+       radeon_ms_execbuffer_args_clean(dev, buffers, args_count);
+       return ret;
+}
+
+static int radeon_ms_execbuffer_check(struct drm_device *dev,
+                                     struct drm_file *file_priv,
+                                     struct drm_radeon_execbuffer *execbuffer,
+                                     struct drm_buffer_object **buffers,
+                                     uint32_t *relocs,
+                                     uint32_t *cmd)
+{
+       uint32_t i, gpu_addr;
+       int ret;
+
+       for (i = 0; i < execbuffer->args_count; i++) {
+               if (relocs[i]) {
+                       ret = radeon_ms_bo_get_gpu_addr(dev, &buffers[i]->mem,
+                                                       &gpu_addr);
+                       if (ret) {
+                               return ret;
+                       }
+                       cmd[relocs[i]] |= (gpu_addr) >> 10;
+               }
+       }
+       for (i = 0; i < execbuffer->cmd_size; i++) {
+#if 0
+               DRM_INFO("cmd[%d]=0x%08X\n", i, cmd[i]);
+#endif
+       }
+       return 0;
+}
+
+int radeon_ms_execbuffer(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
+{
+       struct drm_radeon_execbuffer *execbuffer = data;
+       struct drm_fence_arg *fence_arg = &execbuffer->fence_arg;
+       struct drm_buffer_object **buffers;
+       struct drm_bo_kmap_obj cmd_kmap;
+       struct drm_fence_object *fence;
+       uint32_t *relocs;
+       uint32_t *cmd;
+       int cmd_is_iomem;
+       int ret = 0;
+
+
+       ret = drm_bo_read_lock(&dev->bm.bm_lock);
+       if (ret) {
+               return ret;
+       }
+
+       relocs = drm_calloc(execbuffer->args_count, sizeof(uint32_t),
+                           DRM_MEM_DRIVER);
+       if (relocs == NULL) {
+               drm_bo_read_unlock(&dev->bm.bm_lock);
+               return -ENOMEM;
+        }
+       buffers = drm_calloc(execbuffer->args_count,
+                            sizeof(struct drm_buffer_object *),
+                            DRM_MEM_DRIVER);
+       if (buffers == NULL) {
+               drm_free(relocs, (execbuffer->args_count * sizeof(uint32_t)),
+                        DRM_MEM_DRIVER);
+               drm_bo_read_unlock(&dev->bm.bm_lock);
+               return -ENOMEM;
+        }
+       /* process arguments */
+       ret = radeon_ms_execbuffer_args(dev, file_priv, execbuffer,
+                                       buffers, relocs);
+       if (ret) {
+               DRM_ERROR("[radeon_ms] execbuffer wrong arguments\n");
+               goto out_free;
+       }
+       /* map command buffer */
+       memset(&cmd_kmap, 0, sizeof(struct drm_bo_kmap_obj));
+       ret = drm_bo_kmap(buffers[0],
+                         0,
+                         buffers[0]->mem.num_pages,
+                         &cmd_kmap);
+       if (ret) {
+               DRM_ERROR("[radeon_ms] error mapping ring buffer: %d\n", ret);
+               goto out_free_release;
+       }
+       cmd = drm_bmo_virtual(&cmd_kmap, &cmd_is_iomem);
+       /* do cmd checking & relocations */
+       ret = radeon_ms_execbuffer_check(dev, file_priv, execbuffer,
+                                        buffers, relocs, cmd);
+       if (ret) {
+               drm_putback_buffer_objects(dev);
+               goto out_free_release;
+       }
+
+       ret = radeon_ms_ring_emit(dev, cmd, execbuffer->cmd_size);
+       if (ret) {
+               drm_putback_buffer_objects(dev);
+               goto out_free_release;
+       }
+
+       /* fence */
+       ret = drm_fence_buffer_objects(dev, NULL, 0, NULL, &fence);
+       if (ret) {
+               drm_putback_buffer_objects(dev);
+               DRM_ERROR("[radeon_ms] fence buffer objects failed\n");
+               goto out_free_release;
+       }
+       if (!(fence_arg->flags & DRM_FENCE_FLAG_NO_USER)) {
+               ret = drm_fence_add_user_object(file_priv, fence,
+                                               fence_arg->flags & DRM_FENCE_FLAG_SHAREABLE);
+               if (!ret) {
+                       fence_arg->handle = fence->base.hash.key;
+                       fence_arg->fence_class = fence->fence_class;
+                       fence_arg->type = fence->type;
+                       fence_arg->signaled = fence->signaled;
+                       fence_arg->sequence = fence->sequence;
+               }
+       }
+       drm_fence_usage_deref_unlocked(&fence);
+out_free_release:
+       drm_bo_kunmap(&cmd_kmap);
+       radeon_ms_execbuffer_args_clean(dev, buffers, execbuffer->args_count);
+out_free:
+       drm_free(relocs, (execbuffer->args_count * sizeof(uint32_t)),
+                DRM_MEM_DRIVER);
+       drm_free(buffers,
+                (execbuffer->args_count * sizeof(struct drm_buffer_object *)),
+                DRM_MEM_DRIVER);
+       drm_bo_read_unlock(&dev->bm.bm_lock);
+       return ret;
+}
diff --git a/shared-core/radeon_ms_family.c b/shared-core/radeon_ms_family.c
new file mode 100644 (file)
index 0000000..b70dca2
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ */
+/*
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_ms.h"
+
+extern const uint32_t radeon_cp_microcode[];
+extern const uint32_t r200_cp_microcode[];
+extern const uint32_t r300_cp_microcode[];
+
+static void radeon_flush_cache(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       uint32_t cmd[6];
+       int i, ret;
+
+       cmd[0] = CP_PACKET0(RB2D_DSTCACHE_CTLSTAT, 0);
+       cmd[1] = REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FLUSH, 3);
+       cmd[2] = CP_PACKET0(RB3D_DSTCACHE_CTLSTAT, 0);
+       cmd[3] = REG_S(RB3D_DSTCACHE_CTLSTAT, DC_FLUSH, 3);
+       cmd[4] = CP_PACKET0(RB3D_ZCACHE_CTLSTAT, 0);
+       cmd[5] = RB3D_ZCACHE_CTLSTAT__ZC_FLUSH;
+       /* try to wait but if we timeout we likely are in bad situation */
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               ret = radeon_ms_ring_emit(dev, cmd, 6);
+               if (!ret) {
+                       break;
+               }
+       }
+}
+
+static void r300_flush_cache(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       uint32_t cmd[6];
+       int i, ret;
+
+       cmd[0] = CP_PACKET0(RB2D_DSTCACHE_CTLSTAT, 0);
+       cmd[1] = REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FLUSH, 3);
+       cmd[2] = CP_PACKET0(RB3D_DSTCACHE_CTLSTAT_R3, 0);
+       cmd[3] = REG_S(RB3D_DSTCACHE_CTLSTAT_R3, DC_FLUSH, 3);
+       cmd[4] = CP_PACKET0(RB3D_ZCACHE_CTLSTAT_R3, 0);
+       cmd[5] = RB3D_ZCACHE_CTLSTAT_R3__ZC_FLUSH;
+       /* try to wait but if we timeout we likely are in bad situation */
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               ret = radeon_ms_ring_emit(dev, cmd, 6);
+               if (!ret) {
+                       break;
+               }
+       }
+}
+
+int radeon_ms_family_init(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       int ret;
+
+       dev_priv->microcode = radeon_cp_microcode;
+       dev_priv->irq_emit = radeon_ms_irq_emit;
+
+       switch (dev_priv->family) {
+       case CHIP_R100:
+       case CHIP_R200:
+               dev_priv->microcode = radeon_cp_microcode;
+               dev_priv->flush_cache = radeon_flush_cache;
+               break;
+       case CHIP_RV200:
+       case CHIP_RV250:
+       case CHIP_RV280:
+       case CHIP_RS300:
+               dev_priv->microcode = r200_cp_microcode;
+               dev_priv->flush_cache = radeon_flush_cache;
+               break;
+       case CHIP_R300:
+       case CHIP_R350:
+       case CHIP_R360:
+       case CHIP_RV350:
+       case CHIP_RV370:
+       case CHIP_RV380:
+       case CHIP_RS400:
+       case CHIP_RV410:
+       case CHIP_R420:
+       case CHIP_R430:
+       case CHIP_R480:
+               dev_priv->microcode = r300_cp_microcode;
+               dev_priv->flush_cache = r300_flush_cache;
+               break;
+       default:
+               DRM_ERROR("Unknown radeon family, aborting\n");
+               return -EINVAL;
+       }
+       switch (dev_priv->bus_type) {
+       case RADEON_AGP:
+               dev_priv->create_ttm = drm_agp_init_ttm;
+               dev_priv->bus_init = radeon_ms_agp_init;
+               dev_priv->bus_restore = radeon_ms_agp_restore;
+               dev_priv->bus_save = radeon_ms_agp_save;
+               break;
+       case RADEON_PCIE:
+               dev_priv->create_ttm = radeon_ms_pcie_create_ttm;
+               dev_priv->bus_finish = radeon_ms_pcie_finish;
+               dev_priv->bus_init = radeon_ms_pcie_init;
+               dev_priv->bus_restore = radeon_ms_pcie_restore;
+               dev_priv->bus_save = radeon_ms_pcie_save;
+               break;
+       default:
+               DRM_ERROR("Unknown radeon bus type, aborting\n");
+               return -EINVAL;
+       }
+       ret = radeon_ms_rom_init(dev);
+       if (ret) {
+               return ret;
+       }
+       ret = radeon_ms_properties_init(dev);
+       return ret;
+}
diff --git a/shared-core/radeon_ms_fence.c b/shared-core/radeon_ms_fence.c
new file mode 100644 (file)
index 0000000..6fcf543
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2007 Dave Airlie.
+ * Copyright 2007 Jérôme Glisse
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ *
+ * Authors:
+ *    Dave Airlie
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#include "radeon_ms.h"
+
+static void radeon_ms_fence_flush(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct drm_fence_class_manager *fc = &dev->fm.fence_class[0];
+       uint32_t pending_flush_types = 0;
+       uint32_t sequence;
+
+       if (dev_priv == NULL) {
+               return;
+       }
+       pending_flush_types = fc->pending_flush |
+                             ((fc->pending_exe_flush) ?
+                               DRM_FENCE_TYPE_EXE : 0);
+       if (pending_flush_types) {
+               sequence = mmio_read(dev_priv, dev_priv->fence_reg);
+               drm_fence_handler(dev, 0, sequence, pending_flush_types, 0);
+       }
+}
+
+int radeon_ms_fence_emit_sequence(struct drm_device *dev, uint32_t class,
+                                 uint32_t flags, uint32_t *sequence,
+                                 uint32_t *native_type)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       uint32_t fence_id, cmd[2], i, ret;
+
+       if (!dev_priv || dev_priv->cp_ready != 1) {
+               return -EINVAL;
+       }
+       fence_id = (++dev_priv->fence_id_last);
+       if (dev_priv->fence_id_last > 0x7FFFFFFF) {
+               fence_id = dev_priv->fence_id_last = 1;
+       }
+       *sequence = fence_id;
+       *native_type = DRM_FENCE_TYPE_EXE;
+       if (flags & DRM_RADEON_FENCE_FLAG_FLUSHED) {
+               *native_type |= DRM_RADEON_FENCE_TYPE_RW;
+               dev_priv->flush_cache(dev);
+       }
+       cmd[0] = CP_PACKET0(dev_priv->fence_reg, 0);
+       cmd[1] = fence_id;
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               ret = radeon_ms_ring_emit(dev, cmd, 2);
+               if (!ret) {
+                       dev_priv->irq_emit(dev);
+                       return 0;
+               }
+       }
+       return -EBUSY;
+}
+
+void radeon_ms_fence_handler(struct drm_device * dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct drm_fence_manager *fm = &dev->fm;
+
+       if (dev_priv == NULL) {
+               return;
+       }
+
+       write_lock(&fm->lock);
+       radeon_ms_fence_flush(dev);
+       write_unlock(&fm->lock);
+}
+
+int radeon_ms_fence_has_irq(struct drm_device *dev, uint32_t class,
+                           uint32_t flags)
+{
+       /*
+        * We have an irq that tells us when we have a new breadcrumb.
+        */
+       if (class == 0 && flags == DRM_FENCE_TYPE_EXE)
+               return 1;
+
+       return 0;
+}
+
+int radeon_ms_fence_types(struct drm_buffer_object *bo,
+                         uint32_t *class, uint32_t *type)
+{
+       *class = 0;
+       if (bo->mem.flags & (DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE))
+               *type = 3;
+       else
+               *type = 1;
+       return 0;
+}
+
+void radeon_ms_poke_flush(struct drm_device *dev, uint32_t class)
+{
+       struct drm_fence_manager *fm = &dev->fm;
+       unsigned long flags;
+
+       if (class != 0)
+               return;
+       write_lock_irqsave(&fm->lock, flags);
+       radeon_ms_fence_flush(dev);
+       write_unlock_irqrestore(&fm->lock, flags);
+}
diff --git a/shared-core/radeon_ms_gpu.c b/shared-core/radeon_ms_gpu.c
new file mode 100644 (file)
index 0000000..2868378
--- /dev/null
@@ -0,0 +1,589 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * Copyright 2007 Alex Deucher
+ * Copyright 2007 Dave Airlie
+ * 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.
+ */
+#include "radeon_ms.h"
+
+static int radeon_ms_gpu_address_space_init(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+
+       /* initialize gpu mapping */
+       dev_priv->gpu_vram_start = dev_priv->vram.offset;
+       dev_priv->gpu_vram_end = dev_priv->gpu_vram_start + dev_priv->vram.size;
+       /* align it on 16Mo boundary (clamp memory which is then
+        * unreachable but not manufacturer should use strange
+        * memory size */
+       dev_priv->gpu_vram_end = dev_priv->gpu_vram_end & (~0xFFFFFF);
+       dev_priv->gpu_vram_end -= 1;
+       dev_priv->gpu_vram_size = dev_priv->gpu_vram_end -
+                                 dev_priv->gpu_vram_start + 1;
+       /* set gart size to 32Mo FIXME: should make a parameter for this */
+       dev_priv->gpu_gart_size = 1024 * 1024 * 32;
+       if (dev_priv->gpu_gart_size > (0xffffffffU - dev_priv->gpu_vram_end)) {
+               /* align gart start to next 4Ko in gpu address space */
+               dev_priv->gpu_gart_start = (dev_priv->gpu_vram_end + 1) + 0xfff;
+               dev_priv->gpu_gart_start = dev_priv->gpu_gart_start & (~0xfff);
+               dev_priv->gpu_gart_end = dev_priv->gpu_gart_start +
+                                        dev_priv->gpu_gart_size;
+               dev_priv->gpu_gart_end = (dev_priv->gpu_gart_end & (~0xfff)) -
+                                        0x1000;
+       } else {
+               /* align gart start to next 4Ko in gpu address space */
+               dev_priv->gpu_gart_start = (dev_priv->gpu_vram_start & ~0xfff) -
+                                          dev_priv->gpu_gart_size;
+               dev_priv->gpu_gart_start = dev_priv->gpu_gart_start & (~0xfff);
+               dev_priv->gpu_gart_end = dev_priv->gpu_gart_start +
+                                        dev_priv->gpu_gart_size;
+               dev_priv->gpu_gart_end = (dev_priv->gpu_gart_end & (~0xfff)) -
+                                        0x1000;
+       }
+       state->mc_fb_location =
+               REG_S(MC_FB_LOCATION, MC_FB_START,
+                               dev_priv->gpu_vram_start >> 16) |
+               REG_S(MC_FB_LOCATION, MC_FB_TOP, dev_priv->gpu_vram_end >> 16);
+       state->display_base_addr =
+               REG_S(DISPLAY_BASE_ADDR, DISPLAY_BASE_ADDR,
+                               dev_priv->gpu_vram_start);
+       state->config_aper_0_base = dev_priv->gpu_vram_start;
+       state->config_aper_1_base = dev_priv->gpu_vram_start;
+       state->config_aper_size = dev_priv->gpu_vram_size;
+       DRM_INFO("[radeon_ms] gpu vram start 0x%08X\n",
+                dev_priv->gpu_vram_start);
+       DRM_INFO("[radeon_ms] gpu vram end   0x%08X\n",
+                dev_priv->gpu_vram_end);
+       DRM_INFO("[radeon_ms] gpu gart start 0x%08X\n",
+                dev_priv->gpu_gart_start);
+       DRM_INFO("[radeon_ms] gpu gart end   0x%08X\n",
+                dev_priv->gpu_gart_end);
+       return 0;
+}
+
+static void radeon_ms_gpu_reset(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       uint32_t clock_cntl_index, mclk_cntl, rbbm_soft_reset;
+       uint32_t reset_mask, host_path_cntl, cache_mode;
+
+       radeon_ms_cp_stop(dev);
+       radeon_ms_gpu_flush(dev);
+
+       /* reset clock */
+       clock_cntl_index = MMIO_R(CLOCK_CNTL_INDEX);
+       pll_index_errata(dev_priv);
+       mclk_cntl = PPLL_R(MCLK_CNTL);
+       PPLL_W(MCLK_CNTL,
+                       mclk_cntl |
+                       MCLK_CNTL__FORCE_MCLKA |
+                       MCLK_CNTL__FORCE_MCLKB |
+                       MCLK_CNTL__FORCE_YCLKA |
+                       MCLK_CNTL__FORCE_YCLKB |
+                       MCLK_CNTL__FORCE_MC |
+                       MCLK_CNTL__FORCE_AIC);
+       PPLL_W(SCLK_CNTL,
+                       PPLL_R(SCLK_CNTL) |
+                       SCLK_CNTL__FORCE_CP |
+                       SCLK_CNTL__FORCE_VIP);
+
+       /* Soft resetting HDP thru RBBM_SOFT_RESET register can cause some
+        * unexpected behaviour on some machines.  Here we use
+        * RADEON_HOST_PATH_CNTL to reset it.
+        */
+       host_path_cntl = MMIO_R(HOST_PATH_CNTL);
+       rbbm_soft_reset = MMIO_R(RBBM_SOFT_RESET);
+       reset_mask = RBBM_SOFT_RESET__SOFT_RESET_CP |
+               RBBM_SOFT_RESET__SOFT_RESET_HI |
+               RBBM_SOFT_RESET__SOFT_RESET_VAP |
+               RBBM_SOFT_RESET__SOFT_RESET_SE |
+               RBBM_SOFT_RESET__SOFT_RESET_RE |
+               RBBM_SOFT_RESET__SOFT_RESET_PP |
+               RBBM_SOFT_RESET__SOFT_RESET_E2 |
+               RBBM_SOFT_RESET__SOFT_RESET_RB;
+       MMIO_W(RBBM_SOFT_RESET, rbbm_soft_reset | reset_mask);
+       MMIO_R(RBBM_SOFT_RESET);
+       MMIO_W(RBBM_SOFT_RESET, 0);
+       MMIO_R(RBBM_SOFT_RESET);
+
+       cache_mode = MMIO_R(RB2D_DSTCACHE_MODE);
+       MMIO_W(RB2D_DSTCACHE_MODE,
+                       cache_mode | RB2D_DSTCACHE_MODE__DC_DISABLE_IGNORE_PE);
+
+       MMIO_W(HOST_PATH_CNTL, host_path_cntl | HOST_PATH_CNTL__HDP_SOFT_RESET);
+       MMIO_R(HOST_PATH_CNTL);
+       MMIO_W(HOST_PATH_CNTL, host_path_cntl);
+       MMIO_R(HOST_PATH_CNTL);
+
+       MMIO_W(CLOCK_CNTL_INDEX, clock_cntl_index);
+       pll_index_errata(dev_priv);
+       PPLL_W(MCLK_CNTL, mclk_cntl);
+}
+
+static void radeon_ms_gpu_resume(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       uint32_t a;
+       uint32_t i;
+
+       /* make sure we have sane offset before restoring crtc */
+       a = (MMIO_R(MC_FB_LOCATION) & MC_FB_LOCATION__MC_FB_START__MASK) << 16;
+       MMIO_W(DISPLAY_BASE_ADDR, a);
+       MMIO_W(CRTC2_DISPLAY_BASE_ADDR, a);
+       MMIO_W(CRTC_OFFSET, 0);
+       MMIO_W(CUR_OFFSET, 0);
+       MMIO_W(CRTC_OFFSET_CNTL, CRTC_OFFSET_CNTL__CRTC_OFFSET_FLIP_CNTL);
+       MMIO_W(CRTC2_OFFSET, 0);
+       MMIO_W(CUR2_OFFSET, 0);
+       MMIO_W(CRTC2_OFFSET_CNTL, CRTC2_OFFSET_CNTL__CRTC2_OFFSET_FLIP_CNTL);
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               if (!(CRTC_OFFSET__CRTC_GUI_TRIG_OFFSET &
+                     MMIO_R(CRTC_OFFSET))) {
+                       break;
+               }
+               DRM_UDELAY(1);
+       }
+       if (i >= dev_priv->usec_timeout) {
+               DRM_ERROR("[radeon_ms] timeout waiting for crtc...\n");
+       }
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               if (!(CRTC2_OFFSET__CRTC2_GUI_TRIG_OFFSET &
+                     MMIO_R(CRTC2_OFFSET))) {
+                       break;
+               }
+               DRM_UDELAY(1);
+       }
+       if (i >= dev_priv->usec_timeout) {
+               DRM_ERROR("[radeon_ms] timeout waiting for crtc...\n");
+       }
+       DRM_UDELAY(10000);
+}
+
+static void radeon_ms_gpu_stop(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       uint32_t ov0_scale_cntl, crtc_ext_cntl, crtc_gen_cntl;
+       uint32_t crtc2_gen_cntl, i;
+
+       radeon_ms_wait_for_idle(dev);
+       /* Capture MC_STATUS in case things go wrong ... */
+       ov0_scale_cntl = dev_priv->ov0_scale_cntl = MMIO_R(OV0_SCALE_CNTL);
+       crtc_ext_cntl = dev_priv->crtc_ext_cntl = MMIO_R(CRTC_EXT_CNTL);
+       crtc_gen_cntl = dev_priv->crtc_gen_cntl = MMIO_R(CRTC_GEN_CNTL);
+       crtc2_gen_cntl = dev_priv->crtc2_gen_cntl = MMIO_R(CRTC2_GEN_CNTL);
+       ov0_scale_cntl &= ~OV0_SCALE_CNTL__OV0_OVERLAY_EN__MASK;
+       crtc_ext_cntl |= CRTC_EXT_CNTL__CRTC_DISPLAY_DIS;
+       crtc_gen_cntl &= ~CRTC_GEN_CNTL__CRTC_CUR_EN;
+       crtc_gen_cntl &= ~CRTC_GEN_CNTL__CRTC_ICON_EN;
+       crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_EXT_DISP_EN;
+       crtc_gen_cntl |= CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B;
+       crtc2_gen_cntl &= ~CRTC2_GEN_CNTL__CRTC2_CUR_EN;
+       crtc2_gen_cntl &= ~CRTC2_GEN_CNTL__CRTC2_ICON_EN;
+       crtc2_gen_cntl |= CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B;
+       MMIO_W(OV0_SCALE_CNTL, ov0_scale_cntl);
+       MMIO_W(CRTC_EXT_CNTL, crtc_ext_cntl);
+       MMIO_W(CRTC_GEN_CNTL, crtc_gen_cntl);
+       MMIO_W(CRTC2_GEN_CNTL, crtc2_gen_cntl);
+       DRM_UDELAY(10000);
+       switch (dev_priv->family) {
+       case CHIP_R100:
+       case CHIP_R200:
+       case CHIP_RV200:
+       case CHIP_RV250:
+       case CHIP_RV280:
+       case CHIP_RS300:
+               for (i = 0; i < dev_priv->usec_timeout; i++) {
+                       if ((MC_STATUS__MC_IDLE & MMIO_R(MC_STATUS))) {
+                               DRM_INFO("[radeon_ms] gpu stoped in %d usecs\n",
+                                        i);
+                               return;
+                       }
+                       DRM_UDELAY(1);
+               }
+               break;
+       case CHIP_R300:
+       case CHIP_R350:
+       case CHIP_R360:
+       case CHIP_RV350:
+       case CHIP_RV370:
+       case CHIP_RV380:
+       case CHIP_RS400:
+       case CHIP_RV410:
+       case CHIP_R420:
+       case CHIP_R430:
+       case CHIP_R480:
+               for (i = 0; i < dev_priv->usec_timeout; i++) {
+                       if ((MC_STATUS__MC_IDLE_R3 & MMIO_R(MC_STATUS))) {
+                               DRM_INFO("[radeon_ms] gpu stoped in %d usecs\n",
+                                        i);
+                               return;
+                       }
+                       DRM_UDELAY(1);
+               }
+               break;
+       default:
+               DRM_ERROR("Unknown radeon family, aborting\n");
+               return;
+       }
+       DRM_ERROR("[radeon_ms] failed to stop gpu...will proceed anyway\n");
+       DRM_UDELAY(20000);
+}
+
+static int radeon_ms_wait_for_fifo(struct drm_device *dev, int num_fifo)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       int i;
+
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               int t;
+               t = RBBM_STATUS__CMDFIFO_AVAIL__MASK & MMIO_R(RBBM_STATUS);
+               t = t >> RBBM_STATUS__CMDFIFO_AVAIL__SHIFT;
+               if (t >= num_fifo)
+                       return 0;
+               DRM_UDELAY(1);
+       }
+       DRM_ERROR("[radeon_ms] failed to wait for fifo\n");
+       return -EBUSY;
+}
+
+int radeon_ms_gpu_initialize(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+       int ret;
+
+       state->disp_misc_cntl = DISP_MISC_CNTL__SYNC_PAD_FLOP_EN |
+               REG_S(DISP_MISC_CNTL, SYNC_STRENGTH, 2) |
+               REG_S(DISP_MISC_CNTL, PALETTE_MEM_RD_MARGIN, 0xb) |
+               REG_S(DISP_MISC_CNTL, PALETTE2_MEM_RD_MARGIN, 0xb) |
+               REG_S(DISP_MISC_CNTL, RMX_BUF_MEM_RD_MARGIN, 0x5);
+       state->disp_merge_cntl = REG_S(DISP_MERGE_CNTL, DISP_GRPH_ALPHA, 0xff) |
+               REG_S(DISP_MERGE_CNTL, DISP_OV0_ALPHA, 0xff);
+       state->disp_pwr_man = DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN |
+               DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN |
+               REG_S(DISP_PWR_MAN, DISP_PWR_MAN_DPMS, DISP_PWR_MAN_DPMS__OFF) |
+               DISP_PWR_MAN__DISP_D3_RST |
+               DISP_PWR_MAN__DISP_D3_REG_RST |
+               DISP_PWR_MAN__DISP_D3_GRPH_RST |
+               DISP_PWR_MAN__DISP_D3_SUBPIC_RST |
+               DISP_PWR_MAN__DISP_D3_OV0_RST |
+               DISP_PWR_MAN__DISP_D1D2_GRPH_RST |
+               DISP_PWR_MAN__DISP_D1D2_SUBPIC_RST |
+               DISP_PWR_MAN__DISP_D1D2_OV0_RST |
+               DISP_PWR_MAN__DISP_DVO_ENABLE_RST |
+               DISP_PWR_MAN__TV_ENABLE_RST;
+       state->disp2_merge_cntl = 0;
+       ret = radeon_ms_gpu_address_space_init(dev);
+       if (ret) {
+               return ret;
+       }
+
+       /* initialize bus */
+       ret = dev_priv->bus_init(dev);
+       if (ret != 0) {
+               return ret;
+       }
+       return 0;
+}
+
+void radeon_ms_gpu_dpms(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+
+       if (dev_priv->crtc1_dpms == dev_priv->crtc2_dpms) {
+               /* both crtc are in same state so use global display pwr */
+               state->disp_pwr_man &= ~DISP_PWR_MAN__DISP_PWR_MAN_DPMS__MASK;
+               switch(dev_priv->crtc1_dpms) {
+               case DPMSModeOn:
+                       state->disp_pwr_man |= REG_S(DISP_PWR_MAN,
+                                       DISP_PWR_MAN_DPMS,
+                                       DISP_PWR_MAN_DPMS__ON);
+                       break;
+               case DPMSModeStandby:
+                       state->disp_pwr_man |= REG_S(DISP_PWR_MAN,
+                                       DISP_PWR_MAN_DPMS,
+                                       DISP_PWR_MAN_DPMS__STANDBY);
+                       break;
+               case DPMSModeSuspend:
+                       state->disp_pwr_man |= REG_S(DISP_PWR_MAN,
+                                       DISP_PWR_MAN_DPMS,
+                                       DISP_PWR_MAN_DPMS__SUSPEND);
+                       break;
+               case DPMSModeOff:
+                       state->disp_pwr_man |= REG_S(DISP_PWR_MAN,
+                                       DISP_PWR_MAN_DPMS,
+                                       DISP_PWR_MAN_DPMS__OFF);
+                       break;
+               default:
+                       /* error */
+                       break;
+               }
+               MMIO_W(DISP_PWR_MAN, state->disp_pwr_man);
+       } else {
+               state->disp_pwr_man &= ~DISP_PWR_MAN__DISP_PWR_MAN_DPMS__MASK;
+               state->disp_pwr_man |= REG_S(DISP_PWR_MAN,
+                               DISP_PWR_MAN_DPMS,
+                               DISP_PWR_MAN_DPMS__ON);
+               MMIO_W(DISP_PWR_MAN, state->disp_pwr_man);
+       }
+}
+
+void radeon_ms_gpu_flush(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       uint32_t i;
+       uint32_t purge2d;
+       uint32_t purge3d;
+
+       switch (dev_priv->family) {
+       case CHIP_R100:
+       case CHIP_R200:
+       case CHIP_RV200:
+       case CHIP_RV250:
+       case CHIP_RV280:
+       case CHIP_RS300:
+               purge2d = REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FLUSH, 3) |
+                       REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FREE, 3);
+               purge3d = REG_S(RB3D_DSTCACHE_CTLSTAT, DC_FLUSH, 3) |
+                       REG_S(RB3D_DSTCACHE_CTLSTAT, DC_FREE, 3);
+               MMIO_W(RB2D_DSTCACHE_CTLSTAT, purge2d);
+               MMIO_W(RB3D_DSTCACHE_CTLSTAT, purge3d);
+               break;
+       case CHIP_R300:
+       case CHIP_R350:
+       case CHIP_R360:
+       case CHIP_RV350:
+       case CHIP_RV370:
+       case CHIP_RV380:
+       case CHIP_RS400:
+       case CHIP_RV410:
+       case CHIP_R420:
+       case CHIP_R430:
+       case CHIP_R480:
+               purge2d = REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FLUSH, 3) |
+                       REG_S(RB2D_DSTCACHE_CTLSTAT, DC_FREE, 3);
+               purge3d = REG_S(RB3D_DSTCACHE_CTLSTAT_R3, DC_FLUSH, 3) |
+                       REG_S(RB3D_DSTCACHE_CTLSTAT_R3, DC_FREE, 3);
+               MMIO_W(RB2D_DSTCACHE_CTLSTAT, purge2d);
+               MMIO_W(RB3D_DSTCACHE_CTLSTAT_R3, purge3d);
+               break;
+       default:
+               DRM_ERROR("Unknown radeon family, aborting\n");
+               return;
+       }
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               if (!(RB2D_DSTCACHE_CTLSTAT__DC_BUSY &
+                                       MMIO_R(RB2D_DSTCACHE_CTLSTAT))) {
+                       return;
+               }
+               DRM_UDELAY(1);
+       }
+       DRM_ERROR("[radeon_ms] gpu flush timeout\n");
+}
+
+void radeon_ms_gpu_restore(struct drm_device *dev, struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       uint32_t wait_until;
+       uint32_t fbstart;
+       int ret, ok = 1;
+
+       radeon_ms_gpu_reset(dev);
+       radeon_ms_wait_for_idle(dev);
+       radeon_ms_gpu_stop(dev);
+
+       MMIO_W(AIC_CTRL, state->aic_ctrl);
+       MMIO_W(MC_FB_LOCATION, state->mc_fb_location);
+       MMIO_R(MC_FB_LOCATION);
+       MMIO_W(CONFIG_APER_0_BASE, state->config_aper_0_base);
+       MMIO_W(CONFIG_APER_1_BASE, state->config_aper_1_base);
+       MMIO_W(CONFIG_APER_SIZE, state->config_aper_size);
+       MMIO_W(DISPLAY_BASE_ADDR, state->display_base_addr);
+       if (dev_priv->bus_restore) {
+               dev_priv->bus_restore(dev, state);
+       }
+
+       radeon_ms_gpu_reset(dev);
+       radeon_ms_gpu_resume(dev);
+
+       MMIO_W(BUS_CNTL, state->bus_cntl);
+       wait_until = WAIT_UNTIL__WAIT_DMA_VIPH0_IDLE |
+               WAIT_UNTIL__WAIT_DMA_VIPH1_IDLE |
+               WAIT_UNTIL__WAIT_DMA_VIPH2_IDLE |
+               WAIT_UNTIL__WAIT_DMA_VIPH3_IDLE |
+               WAIT_UNTIL__WAIT_DMA_VID_IDLE |
+               WAIT_UNTIL__WAIT_DMA_GUI_IDLE |
+               WAIT_UNTIL__WAIT_2D_IDLE |
+               WAIT_UNTIL__WAIT_3D_IDLE |
+               WAIT_UNTIL__WAIT_2D_IDLECLEAN |
+               WAIT_UNTIL__WAIT_3D_IDLECLEAN |
+               WAIT_UNTIL__WAIT_HOST_IDLECLEAN;
+       switch (dev_priv->family) {
+       case CHIP_R100:
+       case CHIP_R200:
+       case CHIP_RV200:
+       case CHIP_RV250:
+       case CHIP_RV280:
+       case CHIP_RS300:
+               break;
+       case CHIP_R300:
+       case CHIP_R350:
+       case CHIP_R360:
+       case CHIP_RV350:
+       case CHIP_RV370:
+       case CHIP_RV380:
+       case CHIP_RS400:
+       case CHIP_RV410:
+       case CHIP_R420:
+       case CHIP_R430:
+       case CHIP_R480:
+               wait_until |= WAIT_UNTIL__WAIT_VAP_IDLE;
+               break;
+       }
+       MMIO_W(WAIT_UNTIL, wait_until); 
+       MMIO_W(DISP_MISC_CNTL, state->disp_misc_cntl);
+       MMIO_W(DISP_PWR_MAN, state->disp_pwr_man);
+       MMIO_W(DISP_MERGE_CNTL, state->disp_merge_cntl);
+       MMIO_W(DISP_OUTPUT_CNTL, state->disp_output_cntl);
+       MMIO_W(DISP2_MERGE_CNTL, state->disp2_merge_cntl);
+
+       /* Setup engine location. This shouldn't be necessary since we
+        * set them appropriately before any accel ops, but let's avoid
+        * random bogus DMA in case we inadvertently trigger the engine
+        * in the wrong place (happened).
+        */
+       ret = radeon_ms_wait_for_fifo(dev, 2);
+       if (ret) {
+               ok = 0;
+               DRM_ERROR("[radeon_ms] no fifo for setting up dst & src gui\n");
+               DRM_ERROR("[radeon_ms] proceed anyway\n");
+       }
+       fbstart = (MC_FB_LOCATION__MC_FB_START__MASK &
+                       MMIO_R(MC_FB_LOCATION)) << 16;
+       MMIO_W(DST_PITCH_OFFSET,
+               REG_S(DST_PITCH_OFFSET, DST_OFFSET, fbstart >> 10));
+       MMIO_W(SRC_PITCH_OFFSET,
+               REG_S(SRC_PITCH_OFFSET, SRC_OFFSET, fbstart >> 10));
+
+       ret = radeon_ms_wait_for_fifo(dev, 1);
+       if (ret) {
+               ok = 0;
+               DRM_ERROR("[radeon_ms] no fifo for setting up dp data type\n");
+               DRM_ERROR("[radeon_ms] proceed anyway\n");
+       }
+#ifdef __BIG_ENDIAN
+       MMIO_W(DP_DATATYPE, DP_DATATYPE__DP_BYTE_PIX_ORDER);
+#else
+       MMIO_W(DP_DATATYPE, 0);
+#endif
+
+       ret = radeon_ms_wait_for_fifo(dev, 1);
+       if (ret) {
+               ok = 0;
+               DRM_ERROR("[radeon_ms] no fifo for setting up surface cntl\n");
+               DRM_ERROR("[radeon_ms] proceed anyway\n");
+       }
+       MMIO_W(SURFACE_CNTL, SURFACE_CNTL__SURF_TRANSLATION_DIS);
+
+       ret = radeon_ms_wait_for_fifo(dev, 2);
+       if (ret) {
+               ok = 0;
+               DRM_ERROR("[radeon_ms] no fifo for setting scissor\n");
+               DRM_ERROR("[radeon_ms] proceed anyway\n");
+       }
+       MMIO_W(DEFAULT_SC_BOTTOM_RIGHT, 0x1fff1fff);
+       MMIO_W(DEFAULT2_SC_BOTTOM_RIGHT, 0x1fff1fff);
+
+       ret = radeon_ms_wait_for_fifo(dev, 1);
+       if (ret) {
+               ok = 0;
+               DRM_ERROR("[radeon_ms] no fifo for setting up gui cntl\n");
+               DRM_ERROR("[radeon_ms] proceed anyway\n");
+       }
+       MMIO_W(DP_GUI_MASTER_CNTL, 0);
+
+       ret = radeon_ms_wait_for_fifo(dev, 5);
+       if (ret) {
+               ok = 0;
+               DRM_ERROR("[radeon_ms] no fifo for setting up clear color\n");
+               DRM_ERROR("[radeon_ms] proceed anyway\n");
+       }
+       MMIO_W(DP_BRUSH_BKGD_CLR, 0x00000000);
+       MMIO_W(DP_BRUSH_FRGD_CLR, 0xffffffff);
+       MMIO_W(DP_SRC_BKGD_CLR, 0x00000000);
+       MMIO_W(DP_SRC_FRGD_CLR, 0xffffffff);
+       MMIO_W(DP_WRITE_MSK, 0xffffffff);
+
+       if (!ok) {
+               DRM_ERROR("[radeon_ms] engine restore not enough fifo\n");
+       }
+}
+
+void radeon_ms_gpu_save(struct drm_device *dev, struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       state->aic_ctrl = MMIO_R(AIC_CTRL);
+       state->bus_cntl = MMIO_R(BUS_CNTL);
+       state->mc_fb_location = MMIO_R(MC_FB_LOCATION);
+       state->display_base_addr = MMIO_R(DISPLAY_BASE_ADDR);
+       state->config_aper_0_base = MMIO_R(CONFIG_APER_0_BASE);
+       state->config_aper_1_base = MMIO_R(CONFIG_APER_1_BASE);
+       state->config_aper_size = MMIO_R(CONFIG_APER_SIZE);
+       state->disp_misc_cntl = MMIO_R(DISP_MISC_CNTL);
+       state->disp_pwr_man = MMIO_R(DISP_PWR_MAN);
+       state->disp_merge_cntl = MMIO_R(DISP_MERGE_CNTL);
+       state->disp_output_cntl = MMIO_R(DISP_OUTPUT_CNTL);
+       state->disp2_merge_cntl = MMIO_R(DISP2_MERGE_CNTL);
+       if (dev_priv->bus_save) {
+               dev_priv->bus_save(dev, state);
+       }
+}
+
+int radeon_ms_wait_for_idle(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       int i, j, ret;
+
+       for (i = 0; i < 2; i++) {
+               ret = radeon_ms_wait_for_fifo(dev, 64);
+               if (ret) {
+                       DRM_ERROR("[radeon_ms] fifo not empty\n");
+               }
+               for (j = 0; j < dev_priv->usec_timeout; j++) {
+                       if (!(RBBM_STATUS__GUI_ACTIVE & MMIO_R(RBBM_STATUS))) {
+                               radeon_ms_gpu_flush(dev);
+                               return 0;
+                       }
+                       DRM_UDELAY(1);
+               }
+               DRM_ERROR("[radeon_ms] idle timed out:  status=0x%08x\n",
+                               MMIO_R(RBBM_STATUS));
+               radeon_ms_gpu_stop(dev);
+               radeon_ms_gpu_reset(dev);
+       }
+       return -EBUSY;
+}
diff --git a/shared-core/radeon_ms_i2c.c b/shared-core/radeon_ms_i2c.c
new file mode 100644 (file)
index 0000000..f4468c1
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * Copyright 2007 Alex Deucher
+ * Copyright 2007 Dave Airlie
+ * 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.
+ */
+#include "radeon_ms.h"
+
+static int get_clock(void *data)
+{
+       struct radeon_ms_i2c *i2c = data;
+       struct drm_radeon_private *dev_priv = i2c->drm_dev->dev_private;
+       int v;
+
+       switch (i2c->reg) {
+       case VIPPAD_EN:
+               v = MMIO_R(VIPPAD_Y);
+               if ((REG_G(VIPPAD_Y, VIPPAD_Y_VHAD, v) & 2)) {
+                       v = 1;
+               } else {
+                       v = 0;
+               }
+               break;
+       case VIPPAD1_EN:
+               v = MMIO_R(VIPPAD1_Y);
+               if ((REG_G(VIPPAD1_Y, VIPPAD_Y_DVODATA, v) & 8)) {
+                       v = 1;
+               } else {
+                       v = 0;
+               }
+               break;
+       case GPIO_DDC1:
+               v = MMIO_R(GPIO_DDC1);
+               if ((GPIO_DDC1__DDC1_CLK_INPUT & v)) {
+                       v = 1;
+               } else {
+                       v = 0;
+               }
+               break;
+       case GPIO_DDC2:
+               v = MMIO_R(GPIO_DDC2);
+               if ((GPIO_DDC2__DDC2_CLK_INPUT & v)) {
+                       v = 1;
+               } else {
+                       v = 0;
+               }
+               break;
+       case GPIO_MONID:
+               v = MMIO_R(GPIO_MONID);
+               if ((GPIO_MONID__GPIO_MONID_1_INPUT & v)) {
+                       v = 1;
+               } else {
+                       v = 0;
+               }
+               break;
+       case GPIO_CRT2_DDC:
+               v = MMIO_R(GPIO_CRT2_DDC);
+               if ((GPIO_CRT2_DDC__CRT2_DDC_CLK_INPUT & v)) {
+                       v = 1;
+               } else {
+                       v = 0;
+               }
+               break;
+       default:
+               v = 0;
+               break;
+       }
+       return v;
+}
+
+static int get_data(void *data)
+{
+       struct radeon_ms_i2c *i2c = data;
+       struct drm_radeon_private *dev_priv = i2c->drm_dev->dev_private;
+       int v;
+
+       switch (i2c->reg) {
+       case VIPPAD_EN:
+               v = MMIO_R(VIPPAD_Y);
+               if ((REG_G(VIPPAD_Y, VIPPAD_Y_VHAD, v) & 1)) {
+                       v = 1;
+               } else {
+                       v = 0;
+               }
+               break;
+       case VIPPAD1_EN:
+               v = MMIO_R(VIPPAD1_Y);
+               if ((REG_G(VIPPAD1_Y, VIPPAD_Y_DVODATA, v) & 4)) {
+                       v = 1;
+               } else {
+                       v = 0;
+               }
+               break;
+       case GPIO_DDC1:
+               v = MMIO_R(GPIO_DDC1);
+               if ((GPIO_DDC1__DDC1_DATA_INPUT & v)) {
+                       v = 1;
+               } else {
+                       v = 0;
+               }
+               break;
+       case GPIO_DDC2:
+               v = MMIO_R(GPIO_DDC2);
+               if ((GPIO_DDC2__DDC2_DATA_INPUT & v)) {
+                       v = 1;
+               } else {
+                       v = 0;
+               }
+               break;
+       case GPIO_MONID:
+               v = MMIO_R(GPIO_MONID);
+               if ((GPIO_MONID__GPIO_MONID_0_INPUT & v)) {
+                       v = 1;
+               } else {
+                       v = 0;
+               }
+               break;
+       case GPIO_CRT2_DDC:
+               v = MMIO_R(GPIO_CRT2_DDC);
+               if ((GPIO_CRT2_DDC__CRT2_DDC_DATA_INPUT & v)) {
+                       v = 1;
+               } else {
+                       v = 0;
+               }
+               break;
+       default:
+               v = 0;
+               break;
+       }
+       return v;
+}
+
+static void set_clock(void *i2c_priv, int clock)
+{
+       struct radeon_ms_i2c *i2c = i2c_priv;
+       struct drm_radeon_private *dev_priv = i2c->drm_dev->dev_private;
+       int v, line;
+
+       v = MMIO_R(i2c->reg);
+       switch (i2c->reg) {
+       case VIPPAD_EN:
+               line = REG_G(VIPPAD_EN, VIPPAD_EN_VHAD, v) & ~2;
+               v &= ~VIPPAD_EN__VIPPAD_EN_VHAD__MASK;
+               if (!clock) {
+                       v |= REG_S(VIPPAD_EN, VIPPAD_EN_VHAD, line | 2);
+               } else {
+                       v |= REG_S(VIPPAD_EN, VIPPAD_EN_VHAD, line);
+               }
+               break;
+       case VIPPAD1_EN:
+               line = REG_G(VIPPAD1_EN, VIPPAD_EN_DVODATA, v) & ~8;
+               v &= ~VIPPAD1_EN__VIPPAD_EN_DVODATA__MASK;
+               if (!clock) {
+                       v |= REG_S(VIPPAD1_EN, VIPPAD_EN_DVODATA, line | 8);
+               } else {
+                       v |= REG_S(VIPPAD1_EN, VIPPAD_EN_DVODATA, line);
+               }
+               break;
+       case GPIO_DDC1:
+               v &= ~GPIO_DDC1__DDC1_CLK_OUT_EN;
+               if (!clock) {
+                       v |= GPIO_DDC1__DDC1_CLK_OUT_EN;
+               }
+               break;
+       case GPIO_DDC2:
+               v &= ~GPIO_DDC2__DDC2_CLK_OUT_EN;
+               if (!clock) {
+                       v |= GPIO_DDC2__DDC2_CLK_OUT_EN;
+               }
+               break;
+       case GPIO_MONID:
+               v &= ~GPIO_MONID__GPIO_MONID_1_OUT_EN;
+               if (!clock) {
+                       v |= GPIO_MONID__GPIO_MONID_1_OUT_EN;
+               }
+               break;
+       case GPIO_CRT2_DDC:
+               v &= ~GPIO_CRT2_DDC__CRT2_DDC_CLK_OUT_EN;
+               if (!clock) {
+                       v |= GPIO_CRT2_DDC__CRT2_DDC_CLK_OUT_EN;
+               }
+               break;
+       default:
+               return;
+       }
+       MMIO_W(i2c->reg, v);
+}
+
+static void set_data(void *i2c_priv, int data)
+{
+       struct radeon_ms_i2c *i2c = i2c_priv;
+       struct drm_radeon_private *dev_priv = i2c->drm_dev->dev_private;
+       int v, line;
+
+       v = MMIO_R(i2c->reg);
+       switch (i2c->reg) {
+       case VIPPAD_EN:
+               line = REG_G(VIPPAD_EN, VIPPAD_EN_VHAD, v) & ~1;
+               v &= ~VIPPAD_EN__VIPPAD_EN_VHAD__MASK;
+               if (!data) {
+                       v |= REG_S(VIPPAD_EN, VIPPAD_EN_VHAD, line | 1);
+               } else {
+                       v |= REG_S(VIPPAD_EN, VIPPAD_EN_VHAD, line);
+               }
+               break;
+       case VIPPAD1_EN:
+               line = REG_G(VIPPAD1_EN, VIPPAD_EN_DVODATA, v) & ~4;
+               v &= ~VIPPAD1_EN__VIPPAD_EN_DVODATA__MASK;
+               if (!data) {
+                       v |= REG_S(VIPPAD1_EN, VIPPAD_EN_DVODATA, line | 4);
+               } else {
+                       v |= REG_S(VIPPAD1_EN, VIPPAD_EN_DVODATA, line);
+               }
+               break;
+       case GPIO_DDC1:
+               v &= ~GPIO_DDC1__DDC1_DATA_OUT_EN;
+               if (!data) {
+                       v |= GPIO_DDC1__DDC1_DATA_OUT_EN;
+               }
+               break;
+       case GPIO_DDC2:
+               v &= ~GPIO_DDC2__DDC2_DATA_OUT_EN;
+               if (!data) {
+                       v |= GPIO_DDC2__DDC2_DATA_OUT_EN;
+               }
+               break;
+       case GPIO_MONID:
+               v &= ~GPIO_MONID__GPIO_MONID_0_OUT_EN;
+               if (!data) {
+                       v |= GPIO_MONID__GPIO_MONID_0_OUT_EN;
+               }
+               break;
+       case GPIO_CRT2_DDC:
+               v &= ~GPIO_CRT2_DDC__CRT2_DDC_DATA_OUT_EN;
+               if (!data) {
+                       v |= GPIO_CRT2_DDC__CRT2_DDC_DATA_OUT_EN;
+               }
+               break;
+       default:
+               return;
+       }
+       MMIO_W(i2c->reg, v);
+}
+
+/**
+ * radeon_ms_i2c_create - instantiate an radeon i2c bus on specified GPIO reg
+ * @dev: DRM device
+ * @output: driver specific output device
+ * @reg: GPIO reg to use
+ * @name: name for this bus
+ *
+ * Creates and registers a new i2c bus with the Linux i2c layer, for use
+ * in output probing and control (e.g. DDC or SDVO control functions).
+ *
+ */
+struct radeon_ms_i2c *radeon_ms_i2c_create(struct drm_device *dev,
+                                          const uint32_t reg,
+                                          const char *name)
+{
+       struct radeon_ms_i2c *i2c;
+       int ret;
+
+       i2c = drm_alloc(sizeof(struct radeon_ms_i2c), DRM_MEM_DRIVER);
+       if (i2c == NULL) {
+               return NULL;
+       }
+       memset(i2c, 0, sizeof(struct radeon_ms_i2c));
+
+       i2c->drm_dev = dev;
+       i2c->reg = reg;
+       snprintf(i2c->adapter.name, I2C_NAME_SIZE, "radeon-%s", name);
+       i2c->adapter.owner = THIS_MODULE;
+       /* fixme need to take a look at what its needed for */
+       i2c->adapter.id = I2C_HW_B_RADEON;
+       i2c->adapter.algo_data = &i2c->algo;
+       i2c->adapter.dev.parent = &dev->pdev->dev;
+       i2c->algo.setsda = set_data;
+       i2c->algo.setscl = set_clock;
+       i2c->algo.getsda = get_data;
+       i2c->algo.getscl = get_clock;
+       i2c->algo.udelay = 20;
+       i2c->algo.timeout = usecs_to_jiffies(2200);
+       i2c->algo.data = i2c;
+
+       i2c_set_adapdata(&i2c->adapter, i2c);
+
+       ret = i2c_bit_add_bus(&i2c->adapter);
+       if(ret) {
+               DRM_INFO("[radeon_ms] failed to register I2C '%s' bus (0x%X)\n",
+                        i2c->adapter.name, reg);
+               goto out_free;
+       }
+       DRM_INFO("[radeon_ms] registered I2C '%s' bus (0x%X)\n",
+                i2c->adapter.name, reg);
+       return i2c;
+
+out_free:
+       drm_free(i2c, sizeof(struct radeon_ms_i2c), DRM_MEM_DRIVER);
+       return NULL;
+}
+
+/**
+ * radeon_ms_i2c_destroy - unregister and free i2c bus resources
+ * @output: channel to free
+ *
+ * Unregister the adapter from the i2c layer, then free the structure.
+ */
+void radeon_ms_i2c_destroy(struct radeon_ms_i2c *i2c)
+{
+       if (i2c == NULL) {
+               return;
+       }
+       i2c_del_adapter(&i2c->adapter);
+       drm_free(i2c, sizeof(struct radeon_ms_i2c), DRM_MEM_DRIVER);
+}
diff --git a/shared-core/radeon_ms_irq.c b/shared-core/radeon_ms_irq.c
new file mode 100644 (file)
index 0000000..2f94118
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * Copyright 2007 Alex Deucher
+ * Copyright 2007 Dave Airlie
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ *
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_ms.h"
+
+static uint32_t radeon_ack_irqs(struct drm_radeon_private *dev_priv,
+                               uint32_t mask)
+{
+       uint32_t irqs;
+
+       irqs = MMIO_R(GEN_INT_STATUS);
+       if (irqs) {
+               MMIO_W(GEN_INT_STATUS, irqs);
+       }
+       if (irqs & (~mask)) {
+               /* reprogram irq */
+               MMIO_W(GEN_INT_CNTL, dev_priv->driver_state.gen_int_cntl);
+       }
+       return irqs;
+}
+
+void radeon_ms_irq_emit(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       uint32_t cmd[4];
+       int i, ret;
+
+       cmd[0] = CP_PACKET0(GEN_INT_CNTL, 1);
+       cmd[1] = dev_priv->driver_state.gen_int_cntl | GEN_INT_CNTL__SW_INT_EN;
+       cmd[2] = GEN_INT_STATUS__SW_INT_SET;
+       /* try to wait but if we timeout we likely are in bad situation */
+       for (i = 0; i < dev_priv->usec_timeout; i++) {
+               ret = radeon_ms_ring_emit(dev, cmd, 3);
+               if (!ret) {
+                       break;
+               }
+       }
+}
+
+static void radeon_ms_irq_enable(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+
+       state->gen_int_cntl = GEN_INT_CNTL__SW_INT_EN;
+       radeon_ms_irq_restore(dev, state);
+}
+
+irqreturn_t radeon_ms_irq_handler(DRM_IRQ_ARGS)
+{
+       struct drm_device *dev = (struct drm_device *)arg;
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       uint32_t status, mask;
+
+       /* Only consider the bits we're interested in - others could be used
+        * outside the DRM
+        */
+       mask = GEN_INT_STATUS__SW_INT |
+              GEN_INT_STATUS__CRTC_VBLANK_STAT |
+              GEN_INT_STATUS__CRTC2_VBLANK_STAT;
+       status = radeon_ack_irqs(dev_priv, mask);
+       if (!status) {
+               return IRQ_NONE;
+       }
+
+       /* SW interrupt */
+       if (GEN_INT_STATUS__SW_INT & status) {
+               radeon_ms_fence_handler(dev);
+       }
+       radeon_ms_fence_handler(dev);
+       return IRQ_HANDLED;
+}
+
+void radeon_ms_irq_preinstall(struct drm_device * dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+       uint32_t mask;
+
+       /* Disable *all* interrupts */
+       state->gen_int_cntl = 0;
+       radeon_ms_irq_restore(dev, state);
+
+       /* Clear bits if they're already high */
+       mask = GEN_INT_STATUS__SW_INT |
+              GEN_INT_STATUS__CRTC_VBLANK_STAT |
+              GEN_INT_STATUS__CRTC2_VBLANK_STAT;
+       radeon_ack_irqs(dev_priv, mask);
+}
+
+int radeon_ms_irq_postinstall(struct drm_device * dev)
+{
+       radeon_ms_irq_enable(dev);
+       return 0;
+}
+
+int radeon_ms_irq_init(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+
+       /* Disable *all* interrupts */
+       state->gen_int_cntl = 0;
+       radeon_ms_irq_restore(dev, state);
+       return 0;
+}
+
+void radeon_ms_irq_restore(struct drm_device *dev, struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       MMIO_W(GEN_INT_CNTL, state->gen_int_cntl);
+}
+
+void radeon_ms_irq_save(struct drm_device *dev, struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       state->gen_int_cntl = MMIO_R(GEN_INT_CNTL);
+}
+
+void radeon_ms_irq_uninstall(struct drm_device * dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_state *state = &dev_priv->driver_state;
+
+       if (dev_priv == NULL) {
+               return;
+       }
+
+       /* Disable *all* interrupts */
+       state->gen_int_cntl = 0;
+       radeon_ms_irq_restore(dev, state);
+}
diff --git a/shared-core/radeon_ms_output.c b/shared-core/radeon_ms_output.c
new file mode 100644 (file)
index 0000000..bc17437
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * Copyright 2007 Alex Deucher
+ * Copyright 2007 Dave Airlie
+ * 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.
+ */
+#include "radeon_ms.h"
+
+static struct radeon_ms_output *radeon_ms_connector_get_output(
+               struct drm_radeon_private *dev_priv,
+               struct radeon_ms_connector *connector, int i)
+{
+       if (connector->outputs[i] < 0) {
+               return NULL;
+       }
+       if (connector->outputs[i] >= RADEON_MAX_OUTPUTS) {
+               return NULL;
+       }
+       i = connector->outputs[i];
+       if (dev_priv->outputs[i] == NULL) {
+               return NULL;
+       }
+       if (dev_priv->outputs[i]->connector == NULL) {
+               return dev_priv->outputs[i];
+       }
+       if (dev_priv->outputs[i]->connector == connector) {
+               return dev_priv->outputs[i];
+       }
+       return NULL;
+}
+
+static void radeon_ms_output_dpms(struct drm_output *output, int mode)
+{
+       struct drm_radeon_private *dev_priv = output->dev->dev_private;
+       struct radeon_ms_connector *connector = output->driver_private;
+       struct radeon_ms_output *routput = NULL;
+       int i;
+
+       if (connector == NULL) {
+               return;
+       }
+       for (i = 0; i < RADEON_MAX_OUTPUTS; i++) {
+               routput = radeon_ms_connector_get_output(dev_priv,
+                               connector, i);
+
+               if (routput) {
+                       routput->connector = connector;
+                       routput->dpms(routput, mode);
+               }
+       }
+       radeon_ms_gpu_dpms(output->dev);
+}
+
+static int radeon_ms_output_mode_valid(struct drm_output *output,
+               struct drm_display_mode *mode)
+{
+       struct radeon_ms_connector *connector = output->driver_private;
+
+       if (connector == NULL) {
+               return MODE_ERROR;
+       }
+       return MODE_OK;
+}
+
+static bool radeon_ms_output_mode_fixup(struct drm_output *output,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void radeon_ms_output_prepare(struct drm_output *output)
+{
+       if (output->funcs->dpms) {
+               output->funcs->dpms(output, DPMSModeOff);
+       }
+}
+
+static void radeon_ms_output_commit(struct drm_output *output)
+{
+       if (output->funcs->dpms) {
+               output->funcs->dpms(output, DPMSModeOn);
+       }
+}
+
+static void radeon_ms_output_mode_set(struct drm_output *output,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       struct drm_radeon_private *dev_priv = output->dev->dev_private;
+       struct radeon_ms_connector *connector = output->driver_private;
+       struct radeon_ms_crtc *crtc;
+       struct radeon_ms_output *routput = NULL;
+       int i;
+
+       if (connector == NULL) {
+               return;
+       }
+       if (output->crtc == NULL) {
+               return;
+       }
+       crtc = output->crtc->driver_private;
+       connector->crtc = crtc->crtc;
+       /* catch unknown crtc */
+       switch (connector->crtc) {
+               case 1:
+               case 2:
+                       break;
+               default:
+                       /* error */
+                       return;
+       }
+       for (i = 0; i < RADEON_MAX_OUTPUTS; i++) {
+               routput = radeon_ms_connector_get_output(dev_priv,
+                               connector, i);
+               if (routput) {
+                       routput->connector = connector;
+                       routput->mode_set(routput, mode, adjusted_mode);
+               }
+       }
+}
+
+static enum drm_output_status radeon_ms_output_detect(struct drm_output *output)
+{
+       struct radeon_ms_connector *connector = output->driver_private;
+
+       if (connector == NULL || connector->i2c == NULL) {
+               return output_status_unknown;
+       }
+       kfree(connector->edid);
+       connector->edid = drm_get_edid(output, &connector->i2c->adapter);
+       if (connector->edid == NULL) {
+               return output_status_unknown;
+       }
+       return output_status_connected;
+}
+
+static int radeon_ms_output_get_modes(struct drm_output *output)
+{
+       struct radeon_ms_connector *connector = output->driver_private;
+       int ret = 0;
+
+       if (connector == NULL || connector->i2c == NULL) {
+               return 0;
+       }
+       if (connector->edid == NULL) {
+               return 0;
+       }
+       drm_mode_output_update_edid_property(output, connector->edid);
+       ret = drm_add_edid_modes(output, connector->edid);
+       kfree(connector->edid);
+       connector->edid = NULL;
+       return ret;
+}
+
+static void radeon_ms_output_cleanup(struct drm_output *output)
+{
+       struct radeon_ms_connector *connector = output->driver_private;
+
+       if (connector == NULL) {
+               return;
+       }
+       if (connector->edid) {
+               kfree(connector->edid);
+       }
+       connector->edid = NULL;
+       connector->output = NULL;
+       output->driver_private = NULL;
+}
+
+const struct drm_output_funcs radeon_ms_output_funcs = {
+       .dpms = radeon_ms_output_dpms,
+       .save = NULL,
+       .restore = NULL,
+       .mode_valid = radeon_ms_output_mode_valid,
+       .mode_fixup = radeon_ms_output_mode_fixup,
+       .prepare = radeon_ms_output_prepare,
+       .mode_set = radeon_ms_output_mode_set,
+       .commit = radeon_ms_output_commit,
+       .detect = radeon_ms_output_detect,
+       .get_modes = radeon_ms_output_get_modes,
+       .cleanup = radeon_ms_output_cleanup,
+};
+
+void radeon_ms_connectors_destroy(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_ms_connector *connector = NULL;
+       int i = 0;
+
+       for (i = 0; i < RADEON_MAX_CONNECTORS; i++) {
+               if (dev_priv->connectors[i]) {
+                       connector = dev_priv->connectors[i];
+                       dev_priv->connectors[i] = NULL;
+                       if (connector->output) {
+                               drm_output_destroy(connector->output);
+                               connector->output = NULL;
+                       }
+                       if (connector->i2c) {
+                               radeon_ms_i2c_destroy(connector->i2c);
+                               connector->i2c = NULL;
+                       }
+                       drm_free(connector,
+                                       sizeof(struct radeon_ms_connector),
+                                       DRM_MEM_DRIVER);
+               }
+       }
+}
+
+int radeon_ms_connectors_from_properties(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_ms_connector *connector = NULL;
+       struct drm_output *output = NULL;
+       int i = 0, c = 0;
+
+       radeon_ms_connectors_destroy(dev);
+       for (i = 0; i < RADEON_MAX_CONNECTORS; i++) {
+               if (dev_priv->properties.connectors[i]) {
+                       connector =
+                               drm_alloc(sizeof(struct radeon_ms_connector),
+                                               DRM_MEM_DRIVER);
+                       if (connector == NULL) {
+                               radeon_ms_connectors_destroy(dev);
+                               return -ENOMEM;
+                       }
+                       memcpy(connector, dev_priv->properties.connectors[i],
+                              sizeof(struct radeon_ms_connector));
+                       connector->i2c =
+                               radeon_ms_i2c_create(dev, connector->i2c_reg,
+                                                    connector->name);
+                       if (connector->i2c == NULL) {
+                               radeon_ms_connectors_destroy(dev);
+                               return -ENOMEM;
+                       }
+                       output = drm_output_create(dev,
+                                                  &radeon_ms_output_funcs,
+                                                  connector->type);
+                       if (output == NULL) {
+                               radeon_ms_connectors_destroy(dev);
+                               return -EINVAL;
+                       }
+                       connector->output = output;
+                       output->driver_private = connector;
+                       output->possible_crtcs = 0x3;
+                       dev_priv->connectors[c++] = connector;
+               }
+       }
+       return c;
+}
+
+int radeon_ms_connectors_from_rom(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       switch (dev_priv->rom.type) {
+       case ROM_COMBIOS:
+               return radeon_ms_connectors_from_combios(dev);
+       }
+       return 0;
+}
+
+void radeon_ms_outputs_destroy(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       int i = 0;
+
+       for (i = 0; i < RADEON_MAX_OUTPUTS; i++) {
+               if (dev_priv->outputs[i]) {
+                       drm_free(dev_priv->outputs[i],
+                                       sizeof(struct radeon_ms_output),
+                                       DRM_MEM_DRIVER);
+                       dev_priv->outputs[i] = NULL;
+               }
+       }
+}
+
+int radeon_ms_outputs_from_properties(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       int i = 0;
+       int c = 0;
+
+       radeon_ms_outputs_destroy(dev);
+       for (i = 0; i < RADEON_MAX_OUTPUTS; i++) {
+               if (dev_priv->properties.outputs[i]) {
+                       dev_priv->outputs[i] =
+                               drm_alloc(sizeof(struct radeon_ms_output),
+                                         DRM_MEM_DRIVER);
+                       if (dev_priv->outputs[i] == NULL) {
+                               radeon_ms_outputs_destroy(dev);
+                               return -ENOMEM;
+                       }
+                       memcpy(dev_priv->outputs[i],
+                              dev_priv->properties.outputs[i],
+                              sizeof(struct radeon_ms_output));
+                       dev_priv->outputs[i]->dev = dev;
+                       dev_priv->outputs[i]->initialize(dev_priv->outputs[i]);
+                       c++;
+               }
+       }
+       return c;
+}
+
+int radeon_ms_outputs_from_rom(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       switch (dev_priv->rom.type) {
+       case ROM_COMBIOS:
+               return radeon_ms_outputs_from_combios(dev);
+       }
+       return 0;
+}
+
+void radeon_ms_outputs_restore(struct drm_device *dev,
+               struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       int i;
+
+       for (i = 0; i < RADEON_MAX_OUTPUTS; i++) {
+               if (dev_priv->outputs[i]) {
+                       dev_priv->outputs[i]->restore(dev_priv->outputs[i],
+                                       state);
+               }
+       }
+}
+
+void radeon_ms_outputs_save(struct drm_device *dev, struct radeon_state *state)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       int i;
+
+       for (i = 0; i < RADEON_MAX_OUTPUTS; i++) {
+               if (dev_priv->outputs[i]) {
+                       dev_priv->outputs[i]->save(dev_priv->outputs[i], state);
+               }
+       }
+}
diff --git a/shared-core/radeon_ms_properties.c b/shared-core/radeon_ms_properties.c
new file mode 100644 (file)
index 0000000..baf2a7f
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ */
+/*
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_ms.h"
+
+struct radeon_ms_output radeon_ms_dac1 = {
+       OUTPUT_DAC1,
+       NULL,
+       NULL,
+       radeon_ms_dac1_initialize,
+       radeon_ms_dac1_detect,
+       radeon_ms_dac1_dpms,
+       radeon_ms_dac1_get_modes,
+       radeon_ms_dac1_mode_fixup,
+       radeon_ms_dac1_mode_set,
+       radeon_ms_dac1_restore,
+       radeon_ms_dac1_save
+};
+
+struct radeon_ms_output radeon_ms_dac2 = {
+       OUTPUT_DAC2,
+       NULL,
+       NULL,
+       radeon_ms_dac2_initialize,
+       radeon_ms_dac2_detect,
+       radeon_ms_dac2_dpms,
+       radeon_ms_dac2_get_modes,
+       radeon_ms_dac2_mode_fixup,
+       radeon_ms_dac2_mode_set,
+       radeon_ms_dac2_restore,
+       radeon_ms_dac2_save
+};
+
+struct radeon_ms_connector radeon_ms_vga = {
+       NULL, NULL, NULL, CONNECTOR_VGA, MT_NONE, 0, GPIO_DDC1,
+       {
+               0, -1, -1, -1, -1, -1, -1, -1
+       },
+       "VGA"
+};
+
+struct radeon_ms_connector radeon_ms_dvi_i_2 = {
+       NULL, NULL, NULL, CONNECTOR_DVI_I, MT_NONE, 0, GPIO_DDC2,
+       {
+               1, -1, -1, -1, -1, -1, -1, -1
+       },
+       "DVI-I"
+};
+
+struct radeon_ms_properties properties[] = {
+       /* default only one VGA connector */
+       {
+               0, 0, 27000, 12, 25000, 200000, 1, 1, 1, 1,
+               {
+                       &radeon_ms_dac1, NULL, NULL, NULL, NULL, NULL, NULL,
+                       NULL
+               },
+               {
+                       &radeon_ms_vga, NULL, NULL, NULL, NULL, NULL, NULL,
+                       NULL
+               }
+       }
+};
+
+int radeon_ms_properties_init(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       int i, ret;
+
+       for (i = 1; i < sizeof(properties)/sizeof(properties[0]); i++) {
+               if (dev->pdev->subsystem_vendor == properties[i].subvendor &&
+                   dev->pdev->subsystem_device == properties[i].subdevice) {
+                       DRM_INFO("[radeon_ms] found properties for "
+                                "0x%04X:0x%04X\n", properties[i].subvendor,
+                                properties[i].subdevice);
+                       memcpy(&dev_priv->properties, &properties[i],
+                              sizeof(struct radeon_ms_properties));
+               }
+       }
+       if (dev_priv->properties.subvendor == 0) {
+               ret = radeon_ms_rom_get_properties(dev);
+               if (ret < 0) {
+                       return ret;
+               }
+               if (!ret) {
+                       memcpy(&dev_priv->properties, &properties[0],
+                              sizeof(struct radeon_ms_properties));
+               } else {
+                       dev_priv->properties.pll_dummy_reads = 1;
+                       dev_priv->properties.pll_delay = 1;
+                       dev_priv->properties.pll_r300_errata = 1;
+               }
+               dev_priv->properties.subvendor = dev->pdev->subsystem_vendor;
+               dev_priv->properties.subdevice = dev->pdev->subsystem_device;
+       }
+       return 0;
+}
diff --git a/shared-core/radeon_ms_properties.h b/shared-core/radeon_ms_properties.h
new file mode 100644 (file)
index 0000000..a02a84d
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ */
+/*
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#ifndef __RADEON_MS_PROPERTIES_H__
+#define __RADEON_MS_PROPERTIES_H__
+
+#define RADEON_PAGE_SIZE        4096
+#define RADEON_MAX_CONNECTORS   8
+#define RADEON_MAX_OUTPUTS      8
+
+struct radeon_ms_properties {
+       uint16_t                    subvendor;
+       uint16_t                    subdevice;
+       int16_t                     pll_reference_freq;
+       int16_t                     pll_reference_div;
+       int32_t                     pll_min_pll_freq;
+       int32_t                     pll_max_pll_freq;
+       char                        pll_use_bios;
+       char                        pll_dummy_reads;
+       char                        pll_delay;
+       char                        pll_r300_errata;
+       struct radeon_ms_output     *outputs[RADEON_MAX_OUTPUTS];
+       struct radeon_ms_connector  *connectors[RADEON_MAX_CONNECTORS];
+};
+
+#endif
diff --git a/shared-core/radeon_ms_reg.h b/shared-core/radeon_ms_reg.h
new file mode 100644 (file)
index 0000000..56963c6
--- /dev/null
@@ -0,0 +1,1681 @@
+/*
+ * Copyright 2007  Advanced Micro Devices, Inc.
+ *
+ * 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
+ * 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 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ */
+#ifndef __RADEON_REG_H__
+#define __RADEON_REG_H__
+
+#define MC_FB_LOCATION                                      0x00000148
+#define    MC_FB_LOCATION__MC_FB_START__MASK                    0x0000FFFF
+#define    MC_FB_LOCATION__MC_FB_START__SHIFT                   0
+#define    MC_FB_LOCATION__MC_FB_TOP__MASK                      0xFFFF0000
+#define    MC_FB_LOCATION__MC_FB_TOP__SHIFT                     16
+#define MC_AGP_LOCATION                                     0x0000014C
+#define    MC_AGP_LOCATION__MC_AGP_START__MASK                  0x0000FFFF
+#define    MC_AGP_LOCATION__MC_AGP_START__SHIFT                 0
+#define    MC_AGP_LOCATION__MC_AGP_TOP__MASK                    0xFFFF0000
+#define    MC_AGP_LOCATION__MC_AGP_TOP__SHIFT                   16
+#define AGP_COMMAND                                         0x00000F60
+#define    AGP_COMMAND__DATA_RATE__MASK                         0x00000007
+#define    AGP_COMMAND__DATA_RATE__SHIFT                        0
+#define    DATA_RATE__v2_1X                                         0x1
+#define    DATA_RATE__v2_2X                                         0x2
+#define    DATA_RATE__v2_4X                                         0x4
+#define    DATA_RATE__v3_4X                                         0x1
+#define    DATA_RATE__v3_8X                                         0x2
+#define    AGP_COMMAND__AGP_EN                                  0x00000100
+#define    AGP_COMMAND__SBA_EN                                  0x00000200
+#define    AGP_COMMAND__RQ_DEPTH__MASK                          0xFF000000
+#define    AGP_COMMAND__RQ_DEPTH__SHIFT                         24
+#define    AGP_COMMAND__FW_EN                                   0x00000010
+#define    AGP_COMMAND__MODE_4G_EN                              0x00000020
+#define    AGP_COMMAND__PARQSZ__MASK                            0x0000E000
+#define    AGP_COMMAND__PARQSZ__SHIFT                           13
+#define AGP_STATUS                                          0x00000F5C
+#define    AGP_STATUS__RATE1X                                   0x00000001
+#define    AGP_STATUS__RATE2X                                   0x00000002
+#define    AGP_STATUS__RATE4X                                   0x00000004
+#define    AGP_STATUS__SBA                                      0x00000200
+#define    AGP_STATUS__RQ__MASK                                 0xFF000000
+#define    AGP_STATUS__RQ__SHIFT                                24
+#define    AGP_STATUS__FW                                       0x00000010
+#define    AGP_STATUS__MODE_4G                                  0x00000020
+#define    AGP_STATUS__RATE1X_4X                                0x00000001
+#define    AGP_STATUS__RATE2X_8X                                0x00000002
+#define    AGP_STATUS__MODE_AGP30                               0x00000008
+#define    AGP_STATUS__CAL_CYCLE__MASK                          0x00001C00
+#define    AGP_STATUS__CAL_CYCLE__SHIFT                         10
+#define    AGP_STATUS__ISOCH_SUPPORT                            0x00020000
+#define AGP_BASE                                            0x00000170
+#define    AGP_BASE__AGP_BASE_ADDR__MASK                        0xFFFFFFFF
+#define    AGP_BASE__AGP_BASE_ADDR__SHIFT                       0
+#define AGP_BASE_2                                          0x0000015C
+#define    AGP_BASE_2__AGP_BASE_ADDR_2__MASK                    0x0000000F
+#define    AGP_BASE_2__AGP_BASE_ADDR_2__SHIFT                   0
+#define CONFIG_MEMSIZE                                      0x000000F8
+#define    CONFIG_MEMSIZE__CONFIG_MEMSIZE__MASK                 0x1F000000
+#define    CONFIG_MEMSIZE__CONFIG_MEMSIZE__SHIFT                24
+#define    CONFIG_MEMSIZE__CONFIG_MEMSIZE_R2__MASK              0x1FF00000
+#define    CONFIG_MEMSIZE__CONFIG_MEMSIZE_R2__SHIFT             20
+#define CONFIG_APER_0_BASE                                  0x00000100
+#define    CONFIG_APER_0_BASE__APER_0_BASE__MASK                0xFE000000
+#define    CONFIG_APER_0_BASE__APER_0_BASE__SHIFT               25
+#define CONFIG_APER_1_BASE                                  0x00000104
+#define    CONFIG_APER_1_BASE__APER_1_BASE__MASK                0xFF000000
+#define    CONFIG_APER_1_BASE__APER_1_BASE__SHIFT               24
+#define CONFIG_APER_SIZE                                    0x00000108
+#define    CONFIG_APER_SIZE__APER_SIZE__MASK                    0x0F000000
+#define    CONFIG_APER_SIZE__APER_SIZE__SHIFT                   24
+#define GEN_INT_CNTL                                        0x00000040
+#define    GEN_INT_CNTL__CRTC_VBLANK                            0x00000001
+#define    GEN_INT_CNTL__CRTC_VLINE                             0x00000002
+#define    GEN_INT_CNTL__CRTC_VSYNC                             0x00000004
+#define    GEN_INT_CNTL__SNAPSHOT                               0x00000008
+#define    GEN_INT_CNTL__FP_DETECT                              0x00000010
+#define    GEN_INT_CNTL__CRTC2_VLINE                            0x00000020
+#define    GEN_INT_CNTL__DMA_VIPH0_INT_EN                       0x00001000
+#define    GEN_INT_CNTL__CRTC2_VSYNC                            0x00000040
+#define    GEN_INT_CNTL__SNAPSHOT2                              0x00000080
+#define    GEN_INT_CNTL__CRTC2_VBLANK                           0x00000200
+#define    GEN_INT_CNTL__FP2_DETECT                             0x00000400
+#define    GEN_INT_CNTL__VSYNC_DIFF_OVER_LIMIT                  0x00000800
+#define    GEN_INT_CNTL__DMA_VIPH1_INT_EN                       0x00002000
+#define    GEN_INT_CNTL__DMA_VIPH2_INT_EN                       0x00004000
+#define    GEN_INT_CNTL__DMA_VIPH3_INT_EN                       0x00008000
+#define    GEN_INT_CNTL__I2C_INT_EN                             0x00020000
+#define    GEN_INT_CNTL__GUI_IDLE                               0x00080000
+#define    GEN_INT_CNTL__VIPH_INT_EN                            0x01000000
+#define    GEN_INT_CNTL__SW_INT_EN                              0x02000000
+#define    GEN_INT_CNTL__GEYSERVILLE                            0x08000000
+#define    GEN_INT_CNTL__DVI_I2C_INT                            0x20000000
+#define    GEN_INT_CNTL__GUIDMA                                 0x40000000
+#define    GEN_INT_CNTL__VIDDMA                                 0x80000000
+#define    GEN_INT_CNTL__TIMER_INT                              0x00010000
+#define    GEN_INT_CNTL__IDCT_INT_EN                            0x08000000
+#define GEN_INT_STATUS                                      0x00000044
+#define    GEN_INT_STATUS__CRTC_VBLANK_STAT                     0x00000001
+#define    GEN_INT_STATUS__CRTC_VBLANK_STAT_AK                  0x00000001
+#define    GEN_INT_STATUS__CRTC_VLINE_STAT                      0x00000002
+#define    GEN_INT_STATUS__CRTC_VLINE_STAT_AK                   0x00000002
+#define    GEN_INT_STATUS__CRTC_VSYNC_STAT                      0x00000004
+#define    GEN_INT_STATUS__CRTC_VSYNC_STAT_AK                   0x00000004
+#define    GEN_INT_STATUS__SNAPSHOT_STAT                        0x00000008
+#define    GEN_INT_STATUS__SNAPSHOT_STAT_AK                     0x00000008
+#define    GEN_INT_STATUS__FP_DETECT_STAT                       0x00000010
+#define    GEN_INT_STATUS__FP_DETECT_STAT_AK                    0x00000010
+#define    GEN_INT_STATUS__CRTC2_VLINE_STAT                     0x00000020
+#define    GEN_INT_STATUS__CRTC2_VLINE_STAT_AK                  0x00000020
+#define    GEN_INT_STATUS__CRTC2_VSYNC_STAT                     0x00000040
+#define    GEN_INT_STATUS__CRTC2_VSYNC_STAT_AK                  0x00000040
+#define    GEN_INT_STATUS__SNAPSHOT2_STAT                       0x00000080
+#define    GEN_INT_STATUS__SNAPSHOT2_STAT_AK                    0x00000080
+#define    GEN_INT_STATUS__CAP0_INT_ACTIVE                      0x00000100
+#define    GEN_INT_STATUS__CRTC2_VBLANK_STAT                    0x00000200
+#define    GEN_INT_STATUS__CRTC2_VBLANK_STAT_AK                 0x00000200
+#define    GEN_INT_STATUS__FP2_DETECT_STAT                      0x00000400
+#define    GEN_INT_STATUS__FP2_DETECT_STAT_AK                   0x00000400
+#define    GEN_INT_STATUS__VSYNC_DIFF_OVER_LIMIT_STAT           0x00000800
+#define    GEN_INT_STATUS__VSYNC_DIFF_OVER_LIMIT_STAT_AK        0x00000800
+#define    GEN_INT_STATUS__DMA_VIPH0_INT                        0x00001000
+#define    GEN_INT_STATUS__DMA_VIPH0_INT_AK                     0x00001000
+#define    GEN_INT_STATUS__DMA_VIPH1_INT                        0x00002000
+#define    GEN_INT_STATUS__DMA_VIPH1_INT_AK                     0x00002000
+#define    GEN_INT_STATUS__DMA_VIPH2_INT                        0x00004000
+#define    GEN_INT_STATUS__DMA_VIPH2_INT_AK                     0x00004000
+#define    GEN_INT_STATUS__DMA_VIPH3_INT                        0x00008000
+#define    GEN_INT_STATUS__DMA_VIPH3_INT_AK                     0x00008000
+#define    GEN_INT_STATUS__I2C_INT                              0x00020000
+#define    GEN_INT_STATUS__I2C_INT_AK                           0x00020000
+#define    GEN_INT_STATUS__GUI_IDLE_STAT                        0x00080000
+#define    GEN_INT_STATUS__GUI_IDLE_STAT_AK                     0x00080000
+#define    GEN_INT_STATUS__VIPH_INT                             0x01000000
+#define    GEN_INT_STATUS__SW_INT                               0x02000000
+#define    GEN_INT_STATUS__SW_INT_AK                            0x02000000
+#define    GEN_INT_STATUS__SW_INT_SET                           0x04000000
+#define    GEN_INT_STATUS__GEYSERVILLE_STAT                     0x08000000
+#define    GEN_INT_STATUS__GEYSERVILLE_STAT_AK                  0x08000000
+#define    GEN_INT_STATUS__DVI_I2C_INT_STAT                     0x20000000
+#define    GEN_INT_STATUS__DVI_I2C_INT_AK                       0x20000000
+#define    GEN_INT_STATUS__GUIDMA_STAT                          0x40000000
+#define    GEN_INT_STATUS__GUIDMA_AK                            0x40000000
+#define    GEN_INT_STATUS__VIDDMA_STAT                          0x80000000
+#define    GEN_INT_STATUS__VIDDMA_AK                            0x80000000
+#define    GEN_INT_STATUS__TIMER_INT_STAT                       0x00010000
+#define    GEN_INT_STATUS__TIMER_INT_STAT_AK                    0x00010000
+#define    GEN_INT_STATUS__IDCT_INT_STAT                        0x08000000
+#define    GEN_INT_STATUS__IDCT_INT_STAT_AK                     0x08000000
+#define RB2D_DSTCACHE_MODE                                  0x00003428
+#define    RB2D_DSTCACHE_MODE__DC_BYPASS__MASK                  0x00000003
+#define    RB2D_DSTCACHE_MODE__DC_BYPASS__SHIFT                 0
+#define    RB2D_DSTCACHE_MODE__DC_LINE_SIZE__MASK               0x0000000C
+#define    RB2D_DSTCACHE_MODE__DC_LINE_SIZE__SHIFT              2
+#define    RB2D_DSTCACHE_MODE__DC_AUTOFLUSH_ENABLE__MASK        0x00000300
+#define    RB2D_DSTCACHE_MODE__DC_AUTOFLUSH_ENABLE__SHIFT       8
+#define    RB2D_DSTCACHE_MODE__DC_FORCE_RMW                     0x00010000
+#define    RB2D_DSTCACHE_MODE__DC_DISABLE_RI_FILL               0x01000000
+#define    RB2D_DSTCACHE_MODE__DC_DISABLE_RI_READ               0x02000000
+#define    RB2D_DSTCACHE_MODE__DC_AUTOFREE_ENABLE__MASK         0x00000C00
+#define    RB2D_DSTCACHE_MODE__DC_AUTOFREE_ENABLE__SHIFT        10
+#define    RB2D_DSTCACHE_MODE__DC_DISABLE                       0x04000000
+#define    RB2D_DSTCACHE_MODE__DC_DISABLE_IGNORE_PE             0x00020000
+#define RB2D_DSTCACHE_CTLSTAT                               0x0000342C
+#define    RB2D_DSTCACHE_CTLSTAT__DC_FLUSH__MASK                0x00000003
+#define    RB2D_DSTCACHE_CTLSTAT__DC_FLUSH__SHIFT               0
+#define    RB2D_DSTCACHE_CTLSTAT__DC_FREE__MASK                 0x0000000C
+#define    RB2D_DSTCACHE_CTLSTAT__DC_FREE__SHIFT                2
+#define    RB2D_DSTCACHE_CTLSTAT__DC_BUSY                       0x80000000
+#define RB3D_DSTCACHE_CTLSTAT                               0x0000325C
+#define    RB3D_DSTCACHE_CTLSTAT__DC_FLUSH__MASK                0x00000003
+#define    RB3D_DSTCACHE_CTLSTAT__DC_FLUSH__SHIFT               0
+#define    RB3D_DSTCACHE_CTLSTAT__DC_FREE__MASK                 0x0000000C
+#define    RB3D_DSTCACHE_CTLSTAT__DC_FREE__SHIFT                2
+#define    RB3D_DSTCACHE_CTLSTAT__DC_BUSY                       0x80000000
+#define RB3D_DSTCACHE_CTLSTAT_R3                            0x00004E4C
+#define    RB3D_DSTCACHE_CTLSTAT_R3__DC_FLUSH__MASK             0x00000003
+#define    RB3D_DSTCACHE_CTLSTAT_R3__DC_FLUSH__SHIFT            0
+#define    RB3D_DSTCACHE_CTLSTAT_R3__DC_FREE__MASK              0x0000000C
+#define    RB3D_DSTCACHE_CTLSTAT_R3__DC_FREE__SHIFT             2
+#define    RB3D_DSTCACHE_CTLSTAT_R3__DC_FINISH                  0x00000010
+#define RB3D_ZCACHE_CTLSTAT                                 0x00003254
+#define    RB3D_ZCACHE_CTLSTAT__ZC_FLUSH                        0x00000001
+#define    RB3D_ZCACHE_CTLSTAT__ZC_FREE                         0x00000004
+#define    RB3D_ZCACHE_CTLSTAT__ZC_DIRTY                        0x40000000
+#define    RB3D_ZCACHE_CTLSTAT__ZC_BUSY                         0x80000000
+#define RB3D_ZCACHE_CTLSTAT_R3                              0x00004F18
+#define    RB3D_ZCACHE_CTLSTAT_R3__ZC_FLUSH                     0x00000001
+#define    RB3D_ZCACHE_CTLSTAT_R3__ZC_FREE                      0x00000002
+#define    RB3D_ZCACHE_CTLSTAT_R3__ZC_BUSY                      0x80000000
+#define SCRATCH_REG0                                        0x000015E0
+#define    SCRATCH_REG0__SCRATCH_REG0__MASK                     0xFFFFFFFF
+#define    SCRATCH_REG0__SCRATCH_REG0__SHIFT                    0
+#define SCRATCH_REG1                                        0x000015E4
+#define    SCRATCH_REG1__SCRATCH_REG1__MASK                     0xFFFFFFFF
+#define    SCRATCH_REG1__SCRATCH_REG1__SHIFT                    0
+#define SCRATCH_REG2                                        0x000015E8
+#define    SCRATCH_REG2__SCRATCH_REG2__MASK                     0xFFFFFFFF
+#define    SCRATCH_REG2__SCRATCH_REG2__SHIFT                    0
+#define SCRATCH_REG3                                        0x000015EC
+#define    SCRATCH_REG3__SCRATCH_REG3__MASK                     0xFFFFFFFF
+#define    SCRATCH_REG3__SCRATCH_REG3__SHIFT                    0
+#define SCRATCH_REG4                                        0x000015F0
+#define    SCRATCH_REG4__SCRATCH_REG4__MASK                     0xFFFFFFFF
+#define    SCRATCH_REG4__SCRATCH_REG4__SHIFT                    0
+#define SCRATCH_REG5                                        0x000015F4
+#define    SCRATCH_REG5__SCRATCH_REG5__MASK                     0xFFFFFFFF
+#define    SCRATCH_REG5__SCRATCH_REG5__SHIFT                    0
+#define SCRATCH_REG6                                        0x000015F8
+#define    SCRATCH_REG6__SCRATCH_REG6__MASK                     0xFFFFFFFF
+#define    SCRATCH_REG6__SCRATCH_REG6__SHIFT                    0
+#define SCRATCH_REG7                                        0x000015FC
+#define    SCRATCH_REG7__SCRATCH_REG7__MASK                     0xFFFFFFFF
+#define    SCRATCH_REG7__SCRATCH_REG7__SHIFT                    0
+#define PCIE_INDEX                                          0x00000030
+#define    PCIE_INDEX__PCIE_INDEX__MASK                         0x000007FF
+#define    PCIE_INDEX__PCIE_INDEX__SHIFT                        0
+#define PCIE_DATA                                           0x00000034
+#define    PCIE_DATA__PCIE_DATA__MASK                           0xFFFFFFFF
+#define    PCIE_DATA__PCIE_DATA__SHIFT                          0
+#define PCIE_TX_GART_CNTL                                   0x00000010
+#define    PCIE_TX_GART_CNTL__GART_EN                           0x00000001
+#define    PCIE_TX_GART_CNTL__GART_UNMAPPED_ACCESS__MASK        0x00000006
+#define    PCIE_TX_GART_CNTL__GART_UNMAPPED_ACCESS__SHIFT       1
+#define    GART_UNMAPPED_ACCESS__PTHRU                              0x0
+#define    GART_UNMAPPED_ACCESS__CLAMP                              0x1
+#define    GART_UNMAPPED_ACCESS__DISCARD                            0x3
+#define    PCIE_TX_GART_CNTL__GART_MODE__MASK                   0x00000018
+#define    PCIE_TX_GART_CNTL__GART_MODE__SHIFT                  3
+#define    GART_MODE__CACHE_32x128                                  0x0
+#define    GART_MODE__CACHE_8x4x128                                 0x1
+#define    PCIE_TX_GART_CNTL__GART_CHK_RW_VALID_EN              0x00000020
+#define    PCIE_TX_GART_CNTL__GART_RDREQPATH_SEL__MASK          0x00000040
+#define    PCIE_TX_GART_CNTL__GART_RDREQPATH_SEL__SHIFT         6
+#define    GART_RDREQPATH_SEL__HDP                                  0x0
+#define    GART_RDREQPATH_SEL__DRQMC                                0x1
+#define    PCIE_TX_GART_CNTL__GART_INVALIDATE_TLB               0x00000100
+#define PCIE_TX_GART_DISCARD_RD_ADDR_LO                     0x00000011
+#define    PCIE_TX_GART_DISCARD_RD_ADDR_LO__GART_DISCARD_RD_ADDR_LO__MASK 0xFFFFFFFF
+#define    PCIE_TX_GART_DISCARD_RD_ADDR_LO__GART_DISCARD_RD_ADDR_LO__SHIFT 0
+#define PCIE_TX_GART_DISCARD_RD_ADDR_HI                     0x00000012
+#define    PCIE_TX_GART_DISCARD_RD_ADDR_HI__GART_DISCARD_RD_ADDR_HI__MASK 0x000000FF
+#define    PCIE_TX_GART_DISCARD_RD_ADDR_HI__GART_DISCARD_RD_ADDR_HI__SHIFT 0
+#define PCIE_TX_GART_BASE                                   0x00000013
+#define    PCIE_TX_GART_BASE__GART_BASE__MASK                   0xFFFFFFFF
+#define    PCIE_TX_GART_BASE__GART_BASE__SHIFT                  0
+#define PCIE_TX_GART_START_LO                               0x00000014
+#define    PCIE_TX_GART_START_LO__GART_START_LO__MASK           0xFFFFFFFF
+#define    PCIE_TX_GART_START_LO__GART_START_LO__SHIFT          0
+#define PCIE_TX_GART_START_HI                               0x00000015
+#define    PCIE_TX_GART_START_HI__GART_START_HI__MASK           0x000000FF
+#define    PCIE_TX_GART_START_HI__GART_START_HI__SHIFT          0
+#define PCIE_TX_GART_END_LO                                 0x00000016
+#define    PCIE_TX_GART_END_LO__GART_END_LO__MASK               0xFFFFFFFF
+#define    PCIE_TX_GART_END_LO__GART_END_LO__SHIFT              0
+#define PCIE_TX_GART_END_HI                                 0x00000017
+#define    PCIE_TX_GART_END_HI__GART_END_HI__MASK               0x000000FF
+#define    PCIE_TX_GART_END_HI__GART_END_HI__SHIFT              0
+#define PCIE_TX_GART_ERROR                                  0x00000018
+#define    PCIE_TX_GART_ERROR__GART_UNMAPPED                    0x00000002
+#define    PCIE_TX_GART_ERROR__GART_INVALID_READ                0x00000004
+#define    PCIE_TX_GART_ERROR__GART_INVALID_WRITE               0x00000008
+#define    PCIE_TX_GART_ERROR__GART_INVALID_ADDR__MASK          0xFFFFFFF0
+#define    PCIE_TX_GART_ERROR__GART_INVALID_ADDR__SHIFT         4
+#define CP_RB_CNTL                                          0x00000704
+#define    CP_RB_CNTL__RB_BUFSZ__MASK                           0x0000003F
+#define    CP_RB_CNTL__RB_BUFSZ__SHIFT                          0
+#define    CP_RB_CNTL__RB_BLKSZ__MASK                           0x00003F00
+#define    CP_RB_CNTL__RB_BLKSZ__SHIFT                          8
+#define    CP_RB_CNTL__BUF_SWAP__MASK                           0x00030000
+#define    CP_RB_CNTL__BUF_SWAP__SHIFT                          16
+#define    CP_RB_CNTL__MAX_FETCH__MASK                          0x000C0000
+#define    CP_RB_CNTL__MAX_FETCH__SHIFT                         18
+#define    CP_RB_CNTL__RB_NO_UPDATE                             0x08000000
+#define    CP_RB_CNTL__RB_RPTR_WR_ENA                           0x80000000
+#define CP_RB_BASE                                          0x00000700
+#define    CP_RB_BASE__RB_BASE__MASK                            0xFFFFFFFC
+#define    CP_RB_BASE__RB_BASE__SHIFT                           2
+#define CP_RB_RPTR_ADDR                                     0x0000070C
+#define    CP_RB_RPTR_ADDR__RB_RPTR_SWAP__MASK                  0x00000003
+#define    CP_RB_RPTR_ADDR__RB_RPTR_SWAP__SHIFT                 0
+#define    CP_RB_RPTR_ADDR__RB_RPTR_ADDR__MASK                  0xFFFFFFFC
+#define    CP_RB_RPTR_ADDR__RB_RPTR_ADDR__SHIFT                 2
+#define CP_RB_RPTR                                          0x00000710
+#define    CP_RB_RPTR__RB_RPTR__MASK                            0x007FFFFF
+#define    CP_RB_RPTR__RB_RPTR__SHIFT                           0
+#define CP_RB_RPTR_WR                                       0x0000071C
+#define    CP_RB_RPTR_WR__RB_RPTR_WR__MASK                      0x007FFFFF
+#define    CP_RB_RPTR_WR__RB_RPTR_WR__SHIFT                     0
+#define CP_RB_WPTR                                          0x00000714
+#define    CP_RB_WPTR__RB_WPTR__MASK                            0x007FFFFF
+#define    CP_RB_WPTR__RB_WPTR__SHIFT                           0
+#define CP_RB_WPTR_DELAY                                    0x00000718
+#define    CP_RB_WPTR_DELAY__PRE_WRITE_TIMER__MASK              0x0FFFFFFF
+#define    CP_RB_WPTR_DELAY__PRE_WRITE_TIMER__SHIFT             0
+#define    CP_RB_WPTR_DELAY__PRE_WRITE_LIMIT__MASK              0xF0000000
+#define    CP_RB_WPTR_DELAY__PRE_WRITE_LIMIT__SHIFT             28
+#define SCRATCH_UMSK                                        0x00000770
+#define    SCRATCH_UMSK__SCRATCH_UMSK__MASK                     0x0000003F
+#define    SCRATCH_UMSK__SCRATCH_UMSK__SHIFT                    0
+#define    SCRATCH_UMSK__SCRATCH_SWAP__MASK                     0x00030000
+#define    SCRATCH_UMSK__SCRATCH_SWAP__SHIFT                    16
+#define    SCRATCH_UMSK__SCRATCH_UMSK_R2__MASK                  0x000000FF
+#define    SCRATCH_UMSK__SCRATCH_UMSK_R2__SHIFT                 0
+#define SCRATCH_ADDR                                        0x00000774
+#define    SCRATCH_ADDR__SCRATCH_ADDR__MASK                     0xFFFFFFE0
+#define    SCRATCH_ADDR__SCRATCH_ADDR__SHIFT                    5
+#define CP_ME_RAM_ADDR                                      0x000007D4
+#define    CP_ME_RAM_ADDR__ME_RAM_ADDR__MASK                    0x000000FF
+#define    CP_ME_RAM_ADDR__ME_RAM_ADDR__SHIFT                   0
+#define CP_ME_RAM_DATAH                                     0x000007DC
+#define    CP_ME_RAM_DATAH__ME_RAM_DATAH__MASK                  0x0000003F
+#define    CP_ME_RAM_DATAH__ME_RAM_DATAH__SHIFT                 0
+#define    CP_ME_RAM_DATAH__ME_RAM_DATAH_R3__MASK               0x000000FF
+#define    CP_ME_RAM_DATAH__ME_RAM_DATAH_R3__SHIFT              0
+#define CP_ME_RAM_DATAL                                     0x000007E0
+#define    CP_ME_RAM_DATAL__ME_RAM_DATAL__MASK                  0xFFFFFFFF
+#define    CP_ME_RAM_DATAL__ME_RAM_DATAL__SHIFT                 0
+#define CP_CSQ_CNTL                                         0x00000740
+#define    CP_CSQ_CNTL__CSQ_CNT_PRIMARY__MASK                   0x000000FF
+#define    CP_CSQ_CNTL__CSQ_CNT_PRIMARY__SHIFT                  0
+#define    CP_CSQ_CNTL__CSQ_CNT_INDIRECT__MASK                  0x0000FF00
+#define    CP_CSQ_CNTL__CSQ_CNT_INDIRECT__SHIFT                 8
+#define    CP_CSQ_CNTL__CSQ_MODE__MASK                          0xF0000000
+#define    CP_CSQ_CNTL__CSQ_MODE__SHIFT                         28
+#define    CSQ_MODE__CSQ_PRIDIS_INDDIS                              0x0
+#define    CSQ_MODE__CSQ_PRIPIO_INDDIS                              0x1
+#define    CSQ_MODE__CSQ_PRIBM_INDDIS                               0x2
+#define    CSQ_MODE__CSQ_PRIPIO_INDBM                               0x3
+#define    CSQ_MODE__CSQ_PRIBM_INDBM                                0x4
+#define    CSQ_MODE__CSQ_PRIPIO_INDPIO                              0xF
+#define    CP_CSQ_CNTL__CSQ_CNT_PRIMARY_R2__MASK                0x000001FF
+#define    CP_CSQ_CNTL__CSQ_CNT_PRIMARY_R2__SHIFT               0
+#define    CP_CSQ_CNTL__CSQ_CNT_INDIRECT_R2__MASK               0x0003FE00
+#define    CP_CSQ_CNTL__CSQ_CNT_INDIRECT_R2__SHIFT              9
+#define    CP_CSQ_CNTL__CSQ_CNT_INDIRECT2__MASK                 0x07FC0000
+#define    CP_CSQ_CNTL__CSQ_CNT_INDIRECT2__SHIFT                18
+#define CRTC_GEN_CNTL                                       0x00000050
+#define    CRTC_GEN_CNTL__CRTC_DBL_SCAN_EN                      0x00000001
+#define    CRTC_GEN_CNTL__CRTC_INTERLACE_EN                     0x00000002
+#define    CRTC_GEN_CNTL__CRTC_C_SYNC_EN                        0x00000010
+#define    CRTC_GEN_CNTL__CRTC_PIX_WIDTH__MASK                  0x00000F00
+#define    CRTC_GEN_CNTL__CRTC_PIX_WIDTH__SHIFT                 8
+#define    CRTC_PIX_WIDTH__4BPP                                     0x100
+#define    CRTC_PIX_WIDTH__8BPP                                     0x200
+#define    CRTC_PIX_WIDTH__15BPP                                    0x300
+#define    CRTC_PIX_WIDTH__16BPP                                    0x400
+#define    CRTC_PIX_WIDTH__24BPP                                    0x500
+#define    CRTC_PIX_WIDTH__34BPP                                    0x600
+#define    CRTC_PIX_WIDTH__16BPP_4444                               0x700
+#define    CRTC_PIX_WIDTH__16BPP_88                                 0x800
+#define    CRTC_GEN_CNTL__CRTC_ICON_EN                          0x00008000
+#define    CRTC_GEN_CNTL__CRTC_CUR_EN                           0x00010000
+#define    CRTC_GEN_CNTL__CRTC_VSTAT_MODE__MASK                 0x00060000
+#define    CRTC_GEN_CNTL__CRTC_VSTAT_MODE__SHIFT                17
+#define    CRTC_GEN_CNTL__CRTC_CUR_MODE__MASK                   0x00700000
+#define    CRTC_GEN_CNTL__CRTC_CUR_MODE__SHIFT                  20
+#define    CRTC_CUR_MODE__PREMULTI_ALPHA                            0x2
+#define    CRTC_CUR_MODE__COLOR24BPP                                0x1
+#define    CRTC_GEN_CNTL__CRTC_EXT_DISP_EN                      0x01000000
+#define    CRTC_GEN_CNTL__CRTC_EN                               0x02000000
+#define    CRTC_GEN_CNTL__CRTC_DISP_REQ_EN_B                    0x04000000
+#define    CRTC_GEN_CNTL__CRTC_MODE9_COLOR_ORDER                0x00001000
+#define CRTC_EXT_CNTL                                       0x00000054
+#define    CRTC_EXT_CNTL__CRTC_VGA_XOVERSCAN                    0x00000001
+#define    CRTC_EXT_CNTL__VGA_BLINK_RATE__MASK                  0x00000006
+#define    CRTC_EXT_CNTL__VGA_BLINK_RATE__SHIFT                 1
+#define    CRTC_EXT_CNTL__VGA_ATI_LINEAR                        0x00000008
+#define    CRTC_EXT_CNTL__VGA_128KAP_PAGING                     0x00000010
+#define    CRTC_EXT_CNTL__VGA_TEXT_132                          0x00000020
+#define    CRTC_EXT_CNTL__VGA_XCRT_CNT_EN                       0x00000040
+#define    CRTC_EXT_CNTL__CRTC_HSYNC_DIS                        0x00000100
+#define    CRTC_EXT_CNTL__CRTC_VSYNC_DIS                        0x00000200
+#define    CRTC_EXT_CNTL__CRTC_DISPLAY_DIS                      0x00000400
+#define    CRTC_EXT_CNTL__CRTC_SYNC_TRISTATE                    0x00000800
+#define    CRTC_EXT_CNTL__CRTC_HSYNC_TRISTATE                   0x00001000
+#define    CRTC_EXT_CNTL__CRTC_VSYNC_TRISTATE                   0x00002000
+#define    CRTC_EXT_CNTL__CRT_ON                                0x00008000
+#define    CRTC_EXT_CNTL__VGA_CUR_B_TEST                        0x00020000
+#define    CRTC_EXT_CNTL__VGA_PACK_DIS                          0x00040000
+#define    CRTC_EXT_CNTL__VGA_MEM_PS_EN                         0x00080000
+#define    CRTC_EXT_CNTL__VCRTC_IDX_MASTER__MASK                0x7F000000
+#define    CRTC_EXT_CNTL__VCRTC_IDX_MASTER__SHIFT               24
+#define CRTC_H_TOTAL_DISP                                   0x00000200
+#define    CRTC_H_TOTAL_DISP__CRTC_H_TOTAL__MASK                0x000003FF
+#define    CRTC_H_TOTAL_DISP__CRTC_H_TOTAL__SHIFT               0
+#define    CRTC_H_TOTAL_DISP__CRTC_H_DISP__MASK                 0x01FF0000
+#define    CRTC_H_TOTAL_DISP__CRTC_H_DISP__SHIFT                16
+#define CRTC_H_SYNC_STRT_WID                                0x00000204
+#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_STRT_PIX__MASK     0x00000007
+#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_STRT_PIX__SHIFT    0
+#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_STRT_CHAR__MASK    0x00001FF8
+#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_STRT_CHAR__SHIFT   3
+#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_WID__MASK          0x003F0000
+#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_WID__SHIFT         16
+#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_POL                0x00800000
+#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_SKEW_TUNE__MASK    0x07000000
+#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_SKEW_TUNE__SHIFT   24
+#define    CRTC_H_SYNC_STRT_WID__CRTC_H_SYNC_SKEW_TUNE_MODE     0x10000000
+#define CRTC_V_TOTAL_DISP                                   0x00000208
+#define    CRTC_V_TOTAL_DISP__CRTC_V_TOTAL__MASK                0x00000FFF
+#define    CRTC_V_TOTAL_DISP__CRTC_V_TOTAL__SHIFT               0
+#define    CRTC_V_TOTAL_DISP__CRTC_V_DISP__MASK                 0x0FFF0000
+#define    CRTC_V_TOTAL_DISP__CRTC_V_DISP__SHIFT                16
+#define CRTC_V_SYNC_STRT_WID                                0x0000020C
+#define    CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_STRT__MASK         0x00000FFF
+#define    CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_STRT__SHIFT        0
+#define    CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_WID__MASK          0x001F0000
+#define    CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_WID__SHIFT         16
+#define    CRTC_V_SYNC_STRT_WID__CRTC_V_SYNC_POL                0x00800000
+#define CRTC_OFFSET                                         0x00000224
+#define    CRTC_OFFSET__CRTC_OFFSET__MASK                       0x07FFFFFF
+#define    CRTC_OFFSET__CRTC_OFFSET__SHIFT                      0
+#define    CRTC_OFFSET__CRTC_GUI_TRIG_OFFSET                    0x40000000
+#define    CRTC_OFFSET__CRTC_OFFSET_LOCK                        0x80000000
+#define    CRTC_OFFSET__CRTC_OFFSET_R3__MASK                    0x0FFFFFFF
+#define    CRTC_OFFSET__CRTC_OFFSET_R3__SHIFT                   0
+#define CRTC_OFFSET_CNTL                                    0x00000228
+#define    CRTC_OFFSET_CNTL__CRTC_TILE_LINE__MASK               0x0000000F
+#define    CRTC_OFFSET_CNTL__CRTC_TILE_LINE__SHIFT              0
+#define    CRTC_OFFSET_CNTL__CRTC_TILE_LINE_RIGHT__MASK         0x000000F0
+#define    CRTC_OFFSET_CNTL__CRTC_TILE_LINE_RIGHT__SHIFT        4
+#define    CRTC_OFFSET_CNTL__CRTC_TILE_EN_RIGHT                 0x00004000
+#define    CRTC_OFFSET_CNTL__CRTC_TILE_EN                       0x00008000
+#define    CRTC_OFFSET_CNTL__CRTC_OFFSET_FLIP_CNTL              0x00010000
+#define    CRTC_OFFSET_CNTL__CRTC_STEREO_OFFSET_EN              0x00020000
+#define    CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_EN__MASK          0x000C0000
+#define    CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_EN__SHIFT         18
+#define    CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_OUT_EN            0x00100000
+#define    CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC                   0x00200000
+#define    CRTC_OFFSET_CNTL__CRTC_GUI_TRIG_OFFSET_LEFT_EN       0x10000000
+#define    CRTC_OFFSET_CNTL__CRTC_GUI_TRIG_OFFSET_RIGHT_EN      0x20000000
+#define    CRTC_OFFSET_CNTL__CRTC_GUI_TRIG_OFFSET               0x40000000
+#define    CRTC_OFFSET_CNTL__CRTC_OFFSET_LOCK                   0x80000000
+#define    CRTC_OFFSET_CNTL__CRTC_X_Y_MODE_EN_RIGHT             0x00000040
+#define    CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_BUFFER_MODE_RIGHT__MASK 0x00000180
+#define    CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_BUFFER_MODE_RIGHT__SHIFT 7
+#define    CRTC_OFFSET_CNTL__CRTC_X_Y_MODE_EN                   0x00000200
+#define    CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_BUFFER_MODE__MASK  0x00000C00
+#define    CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_BUFFER_MODE__SHIFT 10
+#define    CRTC_MICRO_TILE_BUFFER_MODE__AUTO                        0x0
+#define    CRTC_MICRO_TILE_BUFFER_MODE__SLINE                       0x1
+#define    CRTC_MICRO_TILE_BUFFER_MODE__DLINE                       0x2
+#define    CRTC_MICRO_TILE_BUFFER_MODE__DIS                         0x3
+#define    CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_EN_RIGHT           0x00001000
+#define    CRTC_OFFSET_CNTL__CRTC_MICRO_TILE_EN                 0x00002000
+#define    CRTC_OFFSET_CNTL__CRTC_MACRO_TILE_EN_RIGHT           0x00004000
+#define    CRTC_OFFSET_CNTL__CRTC_MACRO_TILE_EN                 0x00008000
+#define CRTC_PITCH                                          0x0000022C
+#define    CRTC_PITCH__CRTC_PITCH__MASK                         0x000007FF
+#define    CRTC_PITCH__CRTC_PITCH__SHIFT                        0
+#define    CRTC_PITCH__CRTC_PITCH_RIGHT__MASK                   0x07FF0000
+#define    CRTC_PITCH__CRTC_PITCH_RIGHT__SHIFT                  16
+#define CRTC_MORE_CNTL                                      0x0000027C
+#define    CRTC_MORE_CNTL__CRTC_HORZ_BLANK_MODE_SEL             0x00000001
+#define    CRTC_MORE_CNTL__CRTC_VERT_BLANK_MODE_SEL             0x00000002
+#define    CRTC_MORE_CNTL__CRTC_AUTO_HORZ_CENTER_EN             0x00000004
+#define    CRTC_MORE_CNTL__CRTC_AUTO_VERT_CENTER_EN             0x00000008
+#define    CRTC_MORE_CNTL__CRTC_H_CUTOFF_ACTIVE_EN              0x00000010
+#define    CRTC_MORE_CNTL__CRTC_V_CUTOFF_ACTIVE_EN              0x00000020
+#define    CRTC_MORE_CNTL__FORCE_H_EVEN_PIXEL_COUNT             0x00000040
+#define    CRTC_MORE_CNTL__RMX_H_FILT_COEFFICIENT__MASK         0x07000000
+#define    CRTC_MORE_CNTL__RMX_H_FILT_COEFFICIENT__SHIFT        24
+#define    CRTC_MORE_CNTL__RMX_H_FILTER_EN                      0x08000000
+#define    CRTC_MORE_CNTL__RMX_V_FILT_COEFFICIENT__MASK         0x70000000
+#define    CRTC_MORE_CNTL__RMX_V_FILT_COEFFICIENT__SHIFT        28
+#define    CRTC_MORE_CNTL__RMX_V_FILTER_EN                      0x80000000
+#define    CRTC_MORE_CNTL__DSP_RST_HCOUNT                       0x00000100
+#define    CRTC_MORE_CNTL__DSP_RST_VCOUNT                       0x00000200
+#define    CRTC_MORE_CNTL__HCOUNT_RST_POS                       0x00000400
+#define    CRTC_MORE_CNTL__VCOUNT_RST_POS                       0x00000800
+#define    CRTC_MORE_CNTL__CRTC_FIX_VSYNC_EDGE_POSITION_EN      0x00001000
+#define CRTC_TILE_X0_Y0                                     0x00000350
+#define    CRTC_TILE_X0_Y0__CRTC_TILE_X0__MASK                  0x00000FFF
+#define    CRTC_TILE_X0_Y0__CRTC_TILE_X0__SHIFT                 0
+#define    CRTC_TILE_X0_Y0__CRTC_TILE_Y0__MASK                  0x0FFF0000
+#define    CRTC_TILE_X0_Y0__CRTC_TILE_Y0__SHIFT                 16
+#define    CRTC_TILE_X0_Y0__CRTC_GUI_TRIG_OFFSET                0x40000000
+#define    CRTC_TILE_X0_Y0__CRTC_OFFSET_LOCK                    0x80000000
+#define DAC_CNTL                                            0x00000058
+#define    DAC_CNTL__DAC_RANGE_CNTL__MASK                       0x00000003
+#define    DAC_CNTL__DAC_RANGE_CNTL__SHIFT                      0
+#define    DAC_RANGE_CNTL__PS2                                      0x2
+#define    DAC_RANGE_CNTL__YPbPr                                    0x3
+#define    DAC_CNTL__DAC_BLANKING                               0x00000004
+#define    DAC_CNTL__DAC_CMP_EN                                 0x00000008
+#define    DAC_CNTL__DAC_CMP_OUT_R                              0x00000010
+#define    DAC_CNTL__DAC_CMP_OUT_G                              0x00000020
+#define    DAC_CNTL__DAC_CMP_OUT_B                              0x00000040
+#define    DAC_CNTL__DAC_CMP_OUTPUT                             0x00000080
+#define    DAC_CNTL__DAC_8BIT_EN                                0x00000100
+#define    DAC_CNTL__DAC_4BPP_PIX_ORDER                         0x00000200
+#define    DAC_CNTL__DAC_TVO_EN                                 0x00000400
+#define    DAC_CNTL__DAC_VGA_ADR_EN                             0x00002000
+#define    DAC_CNTL__DAC_EXPAND_MODE                            0x00004000
+#define    DAC_CNTL__DAC_PDWN                                   0x00008000
+#define    DAC_CNTL__CRT_SENSE                                  0x00010000
+#define    DAC_CNTL__CRT_DETECTION_ON                           0x00020000
+#define    DAC_CNTL__DAC_CRC_CONT_EN                            0x00040000
+#define    DAC_CNTL__DAC_CRC_EN                                 0x00080000
+#define    DAC_CNTL__DAC_CRC_FIELD                              0x00100000
+#define    DAC_CNTL__DAC_LUT_COUNTER_LIMIT__MASK                0x00600000
+#define    DAC_CNTL__DAC_LUT_COUNTER_LIMIT__SHIFT               21
+#define    DAC_CNTL__DAC_LUT_READ_SEL                           0x00800000
+#define    DAC_CNTL__DAC__MASK                                  0xFF000000
+#define    DAC_CNTL__DAC__SHIFT                                 24
+#define    DAC_CNTL__DAC_CRC_BLANKb_ONLY                        0x00000800
+#define DAC_CNTL2                                           0x0000007C
+#define    DAC_CNTL2__DAC_CLK_SEL                               0x00000001
+#define    DAC_CNTL2__DAC2_CLK_SEL                              0x00000002
+#define    DAC_CNTL2__PALETTE_ACCESS_CNTL                       0x00000020
+#define    DAC_CNTL2__DAC2_CMP_EN                               0x00000080
+#define    DAC_CNTL2__DAC2_CMP_OUT_R                            0x00000100
+#define    DAC_CNTL2__DAC2_CMP_OUT_G                            0x00000200
+#define    DAC_CNTL2__DAC2_CMP_OUT_B                            0x00000400
+#define    DAC_CNTL2__DAC2_CMP_OUTPUT                           0x00000800
+#define    DAC_CNTL2__DAC2_EXPAND_MODE                          0x00004000
+#define    DAC_CNTL2__CRT2_SENSE                                0x00010000
+#define    DAC_CNTL2__CRT2_DETECTION_ON                         0x00020000
+#define    DAC_CNTL2__DAC_CRC2_CONT_EN                          0x00040000
+#define    DAC_CNTL2__DAC_CRC2_EN                               0x00080000
+#define    DAC_CNTL2__DAC_CRC2_FIELD                            0x00100000
+#define    DAC_CNTL2__DAC2_LUT_COUNTER_LIMIT__MASK              0x00600000
+#define    DAC_CNTL2__DAC2_LUT_COUNTER_LIMIT__SHIFT             21
+#define    DAC_CNTL2__PALETTE_AUTOFILL_PRIMARY_W                0x00000800
+#define    DAC_CNTL2__PALETTE_AUTOFILL_PRIMARY_R                0x00000800
+#define    DAC_CNTL2__PALETTE_AUTOFILL_SECONDARY_W              0x00001000
+#define    DAC_CNTL2__PALETTE_AUTOFILL_SECONDARY_R              0x00001000
+#define    DAC_CNTL2__DAC2_CMP_EN_R3                            0x00000040
+#define    DAC_CNTL2__DAC2_CMP_OUT_R_R3                         0x00000080
+#define    DAC_CNTL2__DAC2_CMP_OUT_G_R3                         0x00000100
+#define    DAC_CNTL2__DAC2_CMP_OUT_B_R3                         0x00000200
+#define    DAC_CNTL2__DAC2_CMP_OUTPUT_R3                        0x00000400
+#define    DAC_CNTL2__DAC_CRC2_BLANKb_ONLY                      0x00020000
+#define DAC_EXT_CNTL                                        0x00000280
+#define    DAC_EXT_CNTL__DAC2_FORCE_BLANK_OFF_EN                0x00000001
+#define    DAC_EXT_CNTL__DAC2_FORCE_DATA_EN                     0x00000002
+#define    DAC_EXT_CNTL__DAC_FORCE_BLANK_OFF_EN                 0x00000010
+#define    DAC_EXT_CNTL__DAC_FORCE_DATA_EN                      0x00000020
+#define    DAC_EXT_CNTL__DAC_FORCE_DATA_SEL__MASK               0x000000C0
+#define    DAC_EXT_CNTL__DAC_FORCE_DATA_SEL__SHIFT              6
+#define    DAC_EXT_CNTL__DAC_FORCE_DATA__MASK                   0x0003FF00
+#define    DAC_EXT_CNTL__DAC_FORCE_DATA__SHIFT                  8
+#define DISP_MISC_CNTL                                      0x00000D00
+#define    DISP_MISC_CNTL__SOFT_RESET_GRPH_PP                   0x00000001
+#define    DISP_MISC_CNTL__SOFT_RESET_SUBPIC_PP                 0x00000002
+#define    DISP_MISC_CNTL__SOFT_RESET_OV0_PP                    0x00000004
+#define    DISP_MISC_CNTL__SOFT_RESET_GRPH_SCLK                 0x00000010
+#define    DISP_MISC_CNTL__SOFT_RESET_SUBPIC_SCLK               0x00000020
+#define    DISP_MISC_CNTL__SOFT_RESET_OV0_SCLK                  0x00000040
+#define    DISP_MISC_CNTL__SYNC_STRENGTH__MASK                  0x00000300
+#define    DISP_MISC_CNTL__SYNC_STRENGTH__SHIFT                 8
+#define    DISP_MISC_CNTL__SYNC_PAD_FLOP_EN                     0x00000400
+#define    DISP_MISC_CNTL__SOFT_RESET_GRPH2_PP                  0x00001000
+#define    DISP_MISC_CNTL__SOFT_RESET_GRPH2_SCLK                0x00008000
+#define    DISP_MISC_CNTL__SOFT_RESET_LVDS                      0x00010000
+#define    DISP_MISC_CNTL__SOFT_RESET_TMDS                      0x00020000
+#define    DISP_MISC_CNTL__SOFT_RESET_DIG_TMDS                  0x00040000
+#define    DISP_MISC_CNTL__SOFT_RESET_TV                        0x00080000
+#define    DISP_MISC_CNTL__PALETTE2_MEM_RD_MARGIN__MASK         0x00F00000
+#define    DISP_MISC_CNTL__PALETTE2_MEM_RD_MARGIN__SHIFT        20
+#define    DISP_MISC_CNTL__PALETTE_MEM_RD_MARGIN__MASK          0x0F000000
+#define    DISP_MISC_CNTL__PALETTE_MEM_RD_MARGIN__SHIFT         24
+#define    DISP_MISC_CNTL__RMX_BUF_MEM_RD_MARGIN__MASK          0xF0000000
+#define    DISP_MISC_CNTL__RMX_BUF_MEM_RD_MARGIN__SHIFT         28
+#define    DISP_MISC_CNTL__SOFT_RESET_DVO                       0x00040000
+#define    DISP_MISC_CNTL__SOFT_RESET_TV_R2                     0x00000800
+#define DAC_MACRO_CNTL                                      0x00000D04
+#define    DAC_MACRO_CNTL__DAC_WHITE_CNTL__MASK                 0x0000000F
+#define    DAC_MACRO_CNTL__DAC_WHITE_CNTL__SHIFT                0
+#define    DAC_MACRO_CNTL__DAC_BG_ADJ__MASK                     0x00000F00
+#define    DAC_MACRO_CNTL__DAC_BG_ADJ__SHIFT                    8
+#define    DAC_MACRO_CNTL__DAC_PDWN_R                           0x00010000
+#define    DAC_MACRO_CNTL__DAC_PDWN_G                           0x00020000
+#define    DAC_MACRO_CNTL__DAC_PDWN_B                           0x00040000
+#define DISP_PWR_MAN                                        0x00000D08
+#define    DISP_PWR_MAN__DISP_PWR_MAN_D3_CRTC_EN                0x00000001
+#define    DISP_PWR_MAN__DISP2_PWR_MAN_D3_CRTC2_EN              0x00000010
+#define    DISP_PWR_MAN__DISP_PWR_MAN_DPMS__MASK                0x00000300
+#define    DISP_PWR_MAN__DISP_PWR_MAN_DPMS__SHIFT               8
+#define    DISP_PWR_MAN_DPMS__ON                                    0x0
+#define    DISP_PWR_MAN_DPMS__STANDBY                               0x1
+#define    DISP_PWR_MAN_DPMS__SUSPEND                               0x2
+#define    DISP_PWR_MAN_DPMS__OFF                                   0x3
+#define    DISP_PWR_MAN__DISP_D3_RST                            0x00010000
+#define    DISP_PWR_MAN__DISP_D3_REG_RST                        0x00020000
+#define    DISP_PWR_MAN__DISP_D3_GRPH_RST                       0x00040000
+#define    DISP_PWR_MAN__DISP_D3_SUBPIC_RST                     0x00080000
+#define    DISP_PWR_MAN__DISP_D3_OV0_RST                        0x00100000
+#define    DISP_PWR_MAN__DISP_D1D2_GRPH_RST                     0x00200000
+#define    DISP_PWR_MAN__DISP_D1D2_SUBPIC_RST                   0x00400000
+#define    DISP_PWR_MAN__DISP_D1D2_OV0_RST                      0x00800000
+#define    DISP_PWR_MAN__DIG_TMDS_ENABLE_RST                    0x01000000
+#define    DISP_PWR_MAN__TV_ENABLE_RST                          0x02000000
+#define    DISP_PWR_MAN__AUTO_PWRUP_EN                          0x04000000
+#define    DISP_PWR_MAN__DISP_DVO_ENABLE_RST                    0x01000000
+#define DISP_MERGE_CNTL                                     0x00000D60
+#define    DISP_MERGE_CNTL__DISP_ALPHA_MODE__MASK               0x00000003
+#define    DISP_MERGE_CNTL__DISP_ALPHA_MODE__SHIFT              0
+#define    DISP_MERGE_CNTL__DISP_ALPHA_INV                      0x00000004
+#define    DISP_MERGE_CNTL__DISP_ALPHA_PREMULT                  0x00000008
+#define    DISP_MERGE_CNTL__DISP_RGB_OFFSET_EN                  0x00000100
+#define    DISP_MERGE_CNTL__DISP_LIN_TRANS_BYPASS               0x00000200
+#define    DISP_MERGE_CNTL__DISP_GRPH_ALPHA__MASK               0x00FF0000
+#define    DISP_MERGE_CNTL__DISP_GRPH_ALPHA__SHIFT              16
+#define    DISP_MERGE_CNTL__DISP_OV0_ALPHA__MASK                0xFF000000
+#define    DISP_MERGE_CNTL__DISP_OV0_ALPHA__SHIFT               24
+#define DISP_OUTPUT_CNTL                                    0x00000D64
+#define    DISP_OUTPUT_CNTL__DISP_DAC_SOURCE__MASK              0x00000003
+#define    DISP_OUTPUT_CNTL__DISP_DAC_SOURCE__SHIFT             0
+#define    DISP_DAC_SOURCE__YPbPr                                   0x3
+#define    DISP_DAC_SOURCE__PRIMARYCRTC                             0x0
+#define    DISP_DAC_SOURCE__SECONDARYCRTC                           0x1
+#define    DISP_DAC_SOURCE__RMX                                     0x2
+#define    DISP_OUTPUT_CNTL__DISP_TRANS_MATRIX_SEL__MASK        0x00000030
+#define    DISP_OUTPUT_CNTL__DISP_TRANS_MATRIX_SEL__SHIFT       4
+#define    DISP_OUTPUT_CNTL__DISP_RMX_SOURCE                    0x00000100
+#define    DISP_OUTPUT_CNTL__DISP_RMX_HTAP_SEL                  0x00000200
+#define    DISP_OUTPUT_CNTL__DISP_RMX_DITH_EN                   0x00000400
+#define    DISP_OUTPUT_CNTL__DISP_TV_SOURCE                     0x00010000
+#define    DISP_OUTPUT_CNTL__DISP_TV_MODE__MASK                 0x00060000
+#define    DISP_OUTPUT_CNTL__DISP_TV_MODE__SHIFT                17
+#define    DISP_OUTPUT_CNTL__DISP_TV_YG_DITH_EN                 0x00080000
+#define    DISP_OUTPUT_CNTL__DISP_TV_CbB_CrR_DITH_EN            0x00100000
+#define    DISP_OUTPUT_CNTL__DISP_TV_BIT_WIDTH                  0x00200000
+#define    DISP_OUTPUT_CNTL__DISP_TV_SYNC_MODE__MASK            0x00C00000
+#define    DISP_OUTPUT_CNTL__DISP_TV_SYNC_MODE__SHIFT           22
+#define    DISP_OUTPUT_CNTL__DISP_TV_SYNC_FORCE                 0x01000000
+#define    DISP_OUTPUT_CNTL__DISP_TV_SYNC_COLOR__MASK           0x06000000
+#define    DISP_OUTPUT_CNTL__DISP_TV_SYNC_COLOR__SHIFT          25
+#define    DISP_OUTPUT_CNTL__DISP_TV_EVEN_FLAG_CNTL__MASK       0x18000000
+#define    DISP_OUTPUT_CNTL__DISP_TV_EVEN_FLAG_CNTL__SHIFT      27
+#define    DISP_OUTPUT_CNTL__DISP_TV_SYNC_STATUS                0x20000000
+#define    DISP_OUTPUT_CNTL__DISP_TV_H_DOWNSCALE                0x40000000
+#define    DISP_OUTPUT_CNTL__DISP_TRANS_SOURCE__MASK            0x00003000
+#define    DISP_OUTPUT_CNTL__DISP_TRANS_SOURCE__SHIFT           12
+#define    DISP_TRANS_SOURCE__PRIMARYCRTC                           0x0
+#define    DISP_TRANS_SOURCE__SECONDARYCRTC                         0x1
+#define    DISP_TRANS_SOURCE__RMX                                   0x2
+#define    DISP_OUTPUT_CNTL__DISP_TVDAC_SOURCE__MASK            0x0000000C
+#define    DISP_OUTPUT_CNTL__DISP_TVDAC_SOURCE__SHIFT           2
+#define    DISP_TVDAC_SOURCE__PRIMARYCRTC                           0x0
+#define    DISP_TVDAC_SOURCE__SECONDARYCRTC                         0x1
+#define    DISP_TVDAC_SOURCE__RMX                                   0x2
+#define    DISP_TVDAC_SOURCE__YPbPr                                 0x3
+#define DISP2_MERGE_CNTL                                    0x00000D68
+#define    DISP2_MERGE_CNTL__DISP2_RGB_OFFSET_EN                0x00000100
+#define DAC_EMBEDDED_SYNC_CNTL                              0x00000DC0
+#define    DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_SYNC_EN_Y_G        0x00000001
+#define    DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_SYNC_EN_Cb_B       0x00000002
+#define    DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_SYNC_EN_Cr_R       0x00000004
+#define    DAC_EMBEDDED_SYNC_CNTL__DAC_TRILEVEL_SYNC_EN         0x00000008
+#define    DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_VSYNC_EN_Y_G       0x00000010
+#define    DAC_EMBEDDED_SYNC_CNTL__DAC_EMBED_VSYNC_EN_CbCr_BR   0x00000020
+#define    DAC_EMBEDDED_SYNC_CNTL__DAC_HSYNC_WID_LSB__MASK      0x00070000
+#define    DAC_EMBEDDED_SYNC_CNTL__DAC_HSYNC_WID_LSB__SHIFT     16
+#define DAC_BROAD_PULSE                                     0x00000DC4
+#define    DAC_BROAD_PULSE__DAC_BROAD_PULSE_START__MASK         0x00001FFF
+#define    DAC_BROAD_PULSE__DAC_BROAD_PULSE_START__SHIFT        0
+#define    DAC_BROAD_PULSE__DAC_BROAD_PULSE_END__MASK           0x1FFF0000
+#define    DAC_BROAD_PULSE__DAC_BROAD_PULSE_END__SHIFT          16
+#define    DAC_BROAD_PULSE__DAC_BROAD_PULSE_START_R2__MASK      0x00000FFF
+#define    DAC_BROAD_PULSE__DAC_BROAD_PULSE_START_R2__SHIFT     0
+#define    DAC_BROAD_PULSE__DAC_BROAD_PULSE_END_R2__MASK        0x0FFF0000
+#define    DAC_BROAD_PULSE__DAC_BROAD_PULSE_END_R2__SHIFT       16
+#define DAC_SKEW_CLKS                                       0x00000DC8
+#define    DAC_SKEW_CLKS__DAC_SKEW_CLKS__MASK                   0x000000FF
+#define    DAC_SKEW_CLKS__DAC_SKEW_CLKS__SHIFT                  0
+#define DAC_INCR                                            0x00000DCC
+#define    DAC_INCR__DAC_INCR_Y_G__MASK                         0x000003FF
+#define    DAC_INCR__DAC_INCR_Y_G__SHIFT                        0
+#define    DAC_INCR__DAC_INCR_CrCb_RB__MASK                     0x03FF0000
+#define    DAC_INCR__DAC_INCR_CrCb_RB__SHIFT                    16
+#define DAC_NEG_SYNC_LEVEL                                  0x00000DD0
+#define    DAC_NEG_SYNC_LEVEL__DAC_NEG_SYNC_LEVEL_Y_G__MASK     0x000003FF
+#define    DAC_NEG_SYNC_LEVEL__DAC_NEG_SYNC_LEVEL_Y_G__SHIFT    0
+#define    DAC_NEG_SYNC_LEVEL__DAC_NEG_SYNC_LEVEL_CrCb_RB__MASK 0x03FF0000
+#define    DAC_NEG_SYNC_LEVEL__DAC_NEG_SYNC_LEVEL_CrCb_RB__SHIFT 16
+#define DAC_POS_SYNC_LEVEL                                  0x00000DD4
+#define    DAC_POS_SYNC_LEVEL__DAC_POS_SYNC_LEVEL_Y_G__MASK     0x000003FF
+#define    DAC_POS_SYNC_LEVEL__DAC_POS_SYNC_LEVEL_Y_G__SHIFT    0
+#define    DAC_POS_SYNC_LEVEL__DAC_POS_SYNC_LEVEL_CrCb_RB__MASK 0x03FF0000
+#define    DAC_POS_SYNC_LEVEL__DAC_POS_SYNC_LEVEL_CrCb_RB__SHIFT 16
+#define DAC_BLANK_LEVEL                                     0x00000DD8
+#define    DAC_BLANK_LEVEL__DAC_BLANK_LEVEL_Y_G__MASK           0x000003FF
+#define    DAC_BLANK_LEVEL__DAC_BLANK_LEVEL_Y_G__SHIFT          0
+#define    DAC_BLANK_LEVEL__DAC_BLANK_LEVEL_CrCb_RB__MASK       0x03FF0000
+#define    DAC_BLANK_LEVEL__DAC_BLANK_LEVEL_CrCb_RB__SHIFT      16
+#define DAC_SYNC_EQUALIZATION                               0x00000DDC
+#define    DAC_SYNC_EQUALIZATION__DAC_SYNC_EQ_START__MASK       0x000007FF
+#define    DAC_SYNC_EQUALIZATION__DAC_SYNC_EQ_START__SHIFT      0
+#define    DAC_SYNC_EQUALIZATION__DAC_SYNC_EQ_END__MASK         0x07FF0000
+#define    DAC_SYNC_EQUALIZATION__DAC_SYNC_EQ_END__SHIFT        16
+#define TV_MASTER_CNTL                                      0x00000800
+#define    TV_MASTER_CNTL__TV_ASYNC_RST                         0x00000001
+#define    TV_MASTER_CNTL__CRT_ASYNC_RST                        0x00000002
+#define    TV_MASTER_CNTL__RESTART_PHASE_FIX                    0x00000008
+#define    TV_MASTER_CNTL__TV_FIFO_ASYNC_RST                    0x00000010
+#define    TV_MASTER_CNTL__MV_BP_LEVEL_FIX_EN                   0x00000020
+#define    TV_MASTER_CNTL__EXTRA_BIT_ONE_0                      0x00000040
+#define    TV_MASTER_CNTL__CRT_FIFO_CE_EN                       0x00000200
+#define    TV_MASTER_CNTL__TV_FIFO_CE_EN                        0x00000400
+#define    TV_MASTER_CNTL__RE_SYNC_NOW_SEL__MASK                0x0000C000
+#define    TV_MASTER_CNTL__RE_SYNC_NOW_SEL__SHIFT               14
+#define    TV_MASTER_CNTL__EXTRA_BIT_ZERO_1                     0x00010000
+#define    TV_MASTER_CNTL__EXTRA_BIT_ONE_1                      0x00020000
+#define    TV_MASTER_CNTL__EXTRA_BIT_ZERO_2                     0x00040000
+#define    TV_MASTER_CNTL__EXTRA_BIT_ONE_2                      0x00080000
+#define    TV_MASTER_CNTL__TVCLK_ALWAYS_ONb                     0x40000000
+#define    TV_MASTER_CNTL__TV_ON                                0x80000000
+#define TV_DAC_CNTL                                         0x0000088C
+#define    TV_DAC_CNTL__NBLANK                                  0x00000001
+#define    TV_DAC_CNTL__NHOLD                                   0x00000002
+#define    TV_DAC_CNTL__PEDESTAL                                0x00000004
+#define    TV_DAC_CNTL__DETECT                                  0x00000010
+#define    TV_DAC_CNTL__CMPOUT                                  0x00000020
+#define    TV_DAC_CNTL__BGSLEEP                                 0x00000040
+#define    TV_DAC_CNTL__STD__MASK                               0x00000300
+#define    TV_DAC_CNTL__STD__SHIFT                              8
+#define    STD__PAL                                                 0x0
+#define    STD__NTSC                                                0x1
+#define    STD__PS2                                                 0x2
+#define    STD__RS343                                               0x3
+#define    TV_DAC_CNTL__MON__MASK                               0x0000F000
+#define    TV_DAC_CNTL__MON__SHIFT                              12
+#define    TV_DAC_CNTL__BGADJ__MASK                             0x000F0000
+#define    TV_DAC_CNTL__BGADJ__SHIFT                            16
+#define    TV_DAC_CNTL__DACADJ__MASK                            0x00F00000
+#define    TV_DAC_CNTL__DACADJ__SHIFT                           20
+#define    TV_DAC_CNTL__RDACPD                                  0x01000000
+#define    TV_DAC_CNTL__GDACPD                                  0x02000000
+#define    TV_DAC_CNTL__BDACPD                                  0x04000000
+#define    TV_DAC_CNTL__RDACDET                                 0x20000000
+#define    TV_DAC_CNTL__GDACDET                                 0x40000000
+#define    TV_DAC_CNTL__BDACDET                                 0x80000000
+#define    TV_DAC_CNTL__DACADJ_R4__MASK                         0x01F00000
+#define    TV_DAC_CNTL__DACADJ_R4__SHIFT                        20
+#define    TV_DAC_CNTL__RDACPD_R4                               0x02000000
+#define    TV_DAC_CNTL__GDACPD_R4                               0x04000000
+#define    TV_DAC_CNTL__BDACPD_R4                               0x08000000
+#define    TV_DAC_CNTL__TVENABLE_R4                             0x10000000
+#define VIPPAD_EN                                           0x000001A0
+#define    VIPPAD_EN__VIPPAD_EN__MASK                           0x0007FFFF
+#define    VIPPAD_EN__VIPPAD_EN__SHIFT                          0
+#define    VIPPAD_EN__VIPPAD_EN_TVODATA__MASK                   0x000003FF
+#define    VIPPAD_EN__VIPPAD_EN_TVODATA__SHIFT                  0
+#define    VIPPAD_EN__VIPPAD_EN_TVOCLKO                         0x00000400
+#define    VIPPAD_EN__VIPPAD_EN_ROMCSb                          0x00000800
+#define    VIPPAD_EN__VIPPAD_EN_VHAD__MASK                      0x00003000
+#define    VIPPAD_EN__VIPPAD_EN_VHAD__SHIFT                     12
+#define    VIPPAD_EN__VIPPAD_EN_VPHCTL                          0x00010000
+#define    VIPPAD_EN__VIPPAD_EN_VIPCLK                          0x00020000
+#define    VIPPAD_EN__VIPPAD_EN_SI                              0x00080000
+#define    VIPPAD_EN__VIPPAD_EN_SO                              0x00100000
+#define    VIPPAD_EN__VIPPAD_EN_SCK                             0x00200000
+#define VIPPAD_Y                                            0x000001A4
+#define    VIPPAD_Y__VIPPAD_Y__MASK                             0x0007FFFF
+#define    VIPPAD_Y__VIPPAD_Y__SHIFT                            0
+#define    VIPPAD_Y__VIPPAD_Y_TVODATA__MASK                     0x000003FF
+#define    VIPPAD_Y__VIPPAD_Y_TVODATA__SHIFT                    0
+#define    VIPPAD_Y__VIPPAD_Y_TVOCLKO                           0x00000400
+#define    VIPPAD_Y__VIPPAD_Y_ROMCSb                            0x00000800
+#define    VIPPAD_Y__VIPPAD_Y_VHAD__MASK                        0x00003000
+#define    VIPPAD_Y__VIPPAD_Y_VHAD__SHIFT                       12
+#define    VIPPAD_Y__VIPPAD_Y_VPHCTL                            0x00010000
+#define    VIPPAD_Y__VIPPAD_Y_VIPCLK                            0x00020000
+#define    VIPPAD_Y__VIPPAD_Y_SI                                0x00080000
+#define    VIPPAD_Y__VIPPAD_Y_SO                                0x00100000
+#define    VIPPAD_Y__VIPPAD_Y_SCK                               0x00200000
+#define VIPPAD1_EN                                          0x000001B0
+#define    VIPPAD1_EN__VIPPAD1_EN__MASK                         0x0003FFFF
+#define    VIPPAD1_EN__VIPPAD1_EN__SHIFT                        0
+#define    VIPPAD1_EN__VIPPAD_EN_VID__MASK                      0x000000FF
+#define    VIPPAD1_EN__VIPPAD_EN_VID__SHIFT                     0
+#define    VIPPAD1_EN__VIPPAD_EN_VPCLK0                         0x00000100
+#define    VIPPAD1_EN__VIPPAD_EN_DVALID                         0x00000200
+#define    VIPPAD1_EN__VIPPAD_EN_PSYNC                          0x00000400
+#define    VIPPAD1_EN__VIPPAD_EN_DVODATA__MASK                  0x0FFF0000
+#define    VIPPAD1_EN__VIPPAD_EN_DVODATA__SHIFT                 16
+#define    VIPPAD1_EN__VIPPAD_EN_DVOCNTL__MASK                  0x70000000
+#define    VIPPAD1_EN__VIPPAD_EN_DVOCNTL__SHIFT                 28
+#define VIPPAD1_Y                                           0x000001B4
+#define    VIPPAD1_Y__VIPPAD1_Y__MASK                           0x0003FFFF
+#define    VIPPAD1_Y__VIPPAD1_Y__SHIFT                          0
+#define    VIPPAD1_Y__VIPPAD_Y_VID__MASK                        0x000000FF
+#define    VIPPAD1_Y__VIPPAD_Y_VID__SHIFT                       0
+#define    VIPPAD1_Y__VIPPAD_Y_VPCLK0                           0x00000100
+#define    VIPPAD1_Y__VIPPAD_Y_DVALID                           0x00000200
+#define    VIPPAD1_Y__VIPPAD_Y_PSYNC                            0x00000400
+#define    VIPPAD1_Y__VIPPAD_Y_DVODATA__MASK                    0x0FFF0000
+#define    VIPPAD1_Y__VIPPAD_Y_DVODATA__SHIFT                   16
+#define    VIPPAD1_Y__VIPPAD_Y_DVOCNTL__MASK                    0x70000000
+#define    VIPPAD1_Y__VIPPAD_Y_DVOCNTL__SHIFT                   28
+#define GPIO_DDC1                                           0x00000060
+#define    GPIO_DDC1__DDC1_DATA_OUTPUT                          0x00000001
+#define    GPIO_DDC1__DDC1_CLK_OUTPUT                           0x00000002
+#define    GPIO_DDC1__DDC1_DATA_INPUT                           0x00000100
+#define    GPIO_DDC1__DDC1_CLK_INPUT                            0x00000200
+#define    GPIO_DDC1__DDC1_DATA_OUT_EN                          0x00010000
+#define    GPIO_DDC1__DDC1_CLK_OUT_EN                           0x00020000
+#define    GPIO_DDC1__SW_WANTS_TO_USE_DVI_I2C                   0x00100000
+#define    GPIO_DDC1__SW_CAN_USE_DVI_I2C                        0x00100000
+#define    GPIO_DDC1__SW_DONE_USING_DVI_I2C                     0x00200000
+#define    GPIO_DDC1__HW_USING_DVI_I2C                          0x00400000
+#define GPIO_DDC2                                           0x00000064
+#define    GPIO_DDC2__DDC2_DATA_OUTPUT                          0x00000001
+#define    GPIO_DDC2__DDC2_CLK_OUTPUT                           0x00000002
+#define    GPIO_DDC2__DDC2_DATA_INPUT                           0x00000100
+#define    GPIO_DDC2__DDC2_CLK_INPUT                            0x00000200
+#define    GPIO_DDC2__DDC2_DATA_OUT_EN                          0x00010000
+#define    GPIO_DDC2__DDC2_CLK_OUT_EN                           0x00020000
+#define    GPIO_DDC2__SW_WANTS_TO_USE_DVI_I2C                   0x00100000
+#define    GPIO_DDC2__SW_CAN_USE_DVI_I2C                        0x00100000
+#define    GPIO_DDC2__SW_DONE_USING_DVI_I2C                     0x00200000
+#define    GPIO_DDC2__HW_USING_DVI_I2C                          0x00400000
+#define GPIO_DVI_DDC                                        0x00000064
+#define    GPIO_DVI_DDC__DVI_DDC_DATA_OUTPUT                    0x00000001
+#define    GPIO_DVI_DDC__DVI_DCC_DATA_OUTPUT                    0x00000001
+#define    GPIO_DVI_DDC__DVI_DDC_CLK_OUTPUT                     0x00000002
+#define    GPIO_DVI_DDC__DVI_DDC_DATA_INPUT                     0x00000100
+#define    GPIO_DVI_DDC__DVI_DDC_CLK_INPUT                      0x00000200
+#define    GPIO_DVI_DDC__DVI_DDC_DATA_OUT_EN                    0x00010000
+#define    GPIO_DVI_DDC__DVI_DDC_CLK_OUT_EN                     0x00020000
+#define    GPIO_DVI_DDC__SW_WANTS_TO_USE_DVI_I2C                0x00100000
+#define    GPIO_DVI_DDC__SW_CAN_USE_DVI_I2C                     0x00100000
+#define    GPIO_DVI_DDC__SW_DONE_USING_DVI_I2C                  0x00200000
+#define    GPIO_DVI_DDC__HW_USING_DVI_I2C                       0x00400000
+#define GPIO_MONID                                          0x00000068
+#define    GPIO_MONID__GPIO_MONID_0_OUTPUT                      0x00000001
+#define    GPIO_MONID__GPIO_MONID_1_OUTPUT                      0x00000002
+#define    GPIO_MONID__GPIO_MONID_0_INPUT                       0x00000100
+#define    GPIO_MONID__GPIO_MONID_1_INPUT                       0x00000200
+#define    GPIO_MONID__GPIO_MONID_0_OUT_EN                      0x00010000
+#define    GPIO_MONID__GPIO_MONID_1_OUT_EN                      0x00020000
+#define GPIO_CRT2_DDC                                       0x0000006C
+#define    GPIO_CRT2_DDC__CRT2_DDC_DATA_OUTPUT                  0x00000001
+#define    GPIO_CRT2_DDC__CRT2_DDC_CLK_OUTPUT                   0x00000002
+#define    GPIO_CRT2_DDC__CRT2_DDC_DATA_INPUT                   0x00000100
+#define    GPIO_CRT2_DDC__CRT2_DDC_CLK_INPUT                    0x00000200
+#define    GPIO_CRT2_DDC__CRT2_DDC_DATA_OUT_EN                  0x00010000
+#define    GPIO_CRT2_DDC__CRT2_DDC_CLK_OUT_EN                   0x00020000
+#define CLOCK_CNTL_INDEX                                    0x00000008
+#define    CLOCK_CNTL_INDEX__PLL_ADDR__MASK                     0x0000001F
+#define    CLOCK_CNTL_INDEX__PLL_ADDR__SHIFT                    0
+#define    CLOCK_CNTL_INDEX__PLL_WR_EN                          0x00000080
+#define    CLOCK_CNTL_INDEX__PPLL_DIV_SEL__MASK                 0x00000300
+#define    CLOCK_CNTL_INDEX__PPLL_DIV_SEL__SHIFT                8
+#define    CLOCK_CNTL_INDEX__PLL_ADDR_R2__MASK                  0x0000003F
+#define    CLOCK_CNTL_INDEX__PLL_ADDR_R2__SHIFT                 0
+#define CLOCK_CNTL_DATA                                     0x0000000C
+#define    CLOCK_CNTL_DATA__PLL_DATA__MASK                      0xFFFFFFFF
+#define    CLOCK_CNTL_DATA__PLL_DATA__SHIFT                     0
+#define MCLK_CNTL                                           0x00000012
+#define    MCLK_CNTL__MCLKA_SRC_SEL__MASK                       0x00000007
+#define    MCLK_CNTL__MCLKA_SRC_SEL__SHIFT                      0
+#define    MCLK_CNTL__YCLKA_SRC_SEL__MASK                       0x00000070
+#define    MCLK_CNTL__YCLKA_SRC_SEL__SHIFT                      4
+#define    MCLK_CNTL__MCLKB_SRC_SEL__MASK                       0x00000700
+#define    MCLK_CNTL__MCLKB_SRC_SEL__SHIFT                      8
+#define    MCLK_CNTL__YCLKB_SRC_SEL__MASK                       0x00007000
+#define    MCLK_CNTL__YCLKB_SRC_SEL__SHIFT                      12
+#define    MCLK_CNTL__FORCE_MCLKA                               0x00010000
+#define    MCLK_CNTL__FORCE_MCLKB                               0x00020000
+#define    MCLK_CNTL__FORCE_YCLKA                               0x00040000
+#define    MCLK_CNTL__FORCE_YCLKB                               0x00080000
+#define    MCLK_CNTL__FORCE_MC                                  0x00100000
+#define    MCLK_CNTL__FORCE_AIC                                 0x00200000
+#define    MCLK_CNTL__MRDCKA0_SOUTSEL__MASK                     0x03000000
+#define    MCLK_CNTL__MRDCKA0_SOUTSEL__SHIFT                    24
+#define    MCLK_CNTL__MRDCKA1_SOUTSEL__MASK                     0x0C000000
+#define    MCLK_CNTL__MRDCKA1_SOUTSEL__SHIFT                    26
+#define    MCLK_CNTL__MRDCKB0_SOUTSEL__MASK                     0x30000000
+#define    MCLK_CNTL__MRDCKB0_SOUTSEL__SHIFT                    28
+#define    MCLK_CNTL__MRDCKB1_SOUTSEL__MASK                     0xC0000000
+#define    MCLK_CNTL__MRDCKB1_SOUTSEL__SHIFT                    30
+#define    MCLK_CNTL__FORCE_MC_MCLKA                            0x00010000
+#define    MCLK_CNTL__FORCE_MC_MCLKB                            0x00020000
+#define    MCLK_CNTL__FORCE_MC_MCLK                             0x00100000
+#define    MCLK_CNTL__DISABLE_MC_MCLKA                          0x00200000
+#define    MCLK_CNTL__DISABLE_MC_MCLKB                          0x00400000
+#define SCLK_CNTL                                           0x0000000D
+#define    SCLK_CNTL__SCLK_SRC_SEL__MASK                        0x00000007
+#define    SCLK_CNTL__SCLK_SRC_SEL__SHIFT                       0
+#define    SCLK_CNTL__TCLK_SRC_SEL__MASK                        0x00000700
+#define    SCLK_CNTL__TCLK_SRC_SEL__SHIFT                       8
+#define    SCLK_CNTL__FORCE_CP                                  0x00010000
+#define    SCLK_CNTL__FORCE_HDP                                 0x00020000
+#define    SCLK_CNTL__FORCE_DISP                                0x00040000
+#define    SCLK_CNTL__FORCE_TOP                                 0x00080000
+#define    SCLK_CNTL__FORCE_E2                                  0x00100000
+#define    SCLK_CNTL__FORCE_SE                                  0x00200000
+#define    SCLK_CNTL__FORCE_IDCT                                0x00400000
+#define    SCLK_CNTL__FORCE_VIP                                 0x00800000
+#define    SCLK_CNTL__FORCE_RE                                  0x01000000
+#define    SCLK_CNTL__FORCE_PB                                  0x02000000
+#define    SCLK_CNTL__FORCE_TAM                                 0x04000000
+#define    SCLK_CNTL__FORCE_TDM                                 0x08000000
+#define    SCLK_CNTL__FORCE_RB                                  0x10000000
+#define    SCLK_CNTL__CP_MAX_DYN_STOP_LAT                       0x00000008
+#define    SCLK_CNTL__HDP_MAX_DYN_STOP_LAT                      0x00000010
+#define    SCLK_CNTL__E2_MAX_DYN_STOP_LAT                       0x00000040
+#define    SCLK_CNTL__SE_MAX_DYN_STOP_LAT                       0x00000080
+#define    SCLK_CNTL__IDCT_MAX_DYN_STOP_LAT                     0x00000100
+#define    SCLK_CNTL__VIP_MAX_DYN_STOP_LAT                      0x00000200
+#define    SCLK_CNTL__RE_MAX_DYN_STOP_LAT                       0x00000400
+#define    SCLK_CNTL__PB_MAX_DYN_STOP_LAT                       0x00000800
+#define    SCLK_CNTL__TAM_MAX_DYN_STOP_LAT                      0x00001000
+#define    SCLK_CNTL__TDM_MAX_DYN_STOP_LAT                      0x00002000
+#define    SCLK_CNTL__RB_MAX_DYN_STOP_LAT                       0x00004000
+#define    SCLK_CNTL__FORCE_DISP2                               0x00008000
+#define    SCLK_CNTL__FORCE_DISP1                               0x00040000
+#define    SCLK_CNTL__FORCE_SUBPIC                              0x40000000
+#define    SCLK_CNTL__FORCE_OV0                                 0x80000000
+#define    SCLK_CNTL__TV_MAX_DYN_STOP_LAT                       0x00000020
+#define    SCLK_CNTL__FORCE_TV_SCLK                             0x20000000
+#define    SCLK_CNTL__VAP_MAX_DYN_STOP_LAT                      0x00000080
+#define    SCLK_CNTL__SR_MAX_DYN_STOP_LAT                       0x00000400
+#define    SCLK_CNTL__PX_MAX_DYN_STOP_LAT                       0x00000800
+#define    SCLK_CNTL__TX_MAX_DYN_STOP_LAT                       0x00001000
+#define    SCLK_CNTL__US_MAX_DYN_STOP_LAT                       0x00002000
+#define    SCLK_CNTL__SU_MAX_DYN_STOP_LAT                       0x00004000
+#define    SCLK_CNTL__FORCE_VAP                                 0x00200000
+#define    SCLK_CNTL__FORCE_SR                                  0x02000000
+#define    SCLK_CNTL__FORCE_PX                                  0x04000000
+#define    SCLK_CNTL__FORCE_TX                                  0x08000000
+#define    SCLK_CNTL__FORCE_US                                  0x10000000
+#define    SCLK_CNTL__FORCE_SU                                  0x40000000
+#define PPLL_CNTL                                           0x00000002
+#define    PPLL_CNTL__PPLL_RESET                                0x00000001
+#define    PPLL_CNTL__PPLL_SLEEP                                0x00000002
+#define    PPLL_CNTL__PPLL_TST_EN                               0x00000004
+#define    PPLL_CNTL__PPLL_REFCLK_SEL                           0x00000010
+#define    PPLL_CNTL__PPLL_FBCLK_SEL                            0x00000020
+#define    PPLL_CNTL__PPLL_TCPOFF                               0x00000040
+#define    PPLL_CNTL__PPLL_TVCOMAX                              0x00000080
+#define    PPLL_CNTL__PPLL_PCP__MASK                            0x00000700
+#define    PPLL_CNTL__PPLL_PCP__SHIFT                           8
+#define    PPLL_CNTL__PPLL_PVG__MASK                            0x00003800
+#define    PPLL_CNTL__PPLL_PVG__SHIFT                           11
+#define    PPLL_CNTL__PPLL_PDC__MASK                            0x0000C000
+#define    PPLL_CNTL__PPLL_PDC__SHIFT                           14
+#define    PPLL_CNTL__PPLL_ATOMIC_UPDATE_EN                     0x00010000
+#define    PPLL_CNTL__PPLL_VGA_ATOMIC_UPDATE_EN                 0x00020000
+#define    PPLL_CNTL__PPLL_ATOMIC_UPDATE_SYNC                   0x00040000
+#define    PPLL_CNTL__PPLL_DISABLE_AUTO_RESET                   0x00080000
+#define    PPLL_CNTL__PPLL_DIV_RESET                            0x00000008
+#define PPLL_REF_DIV                                        0x00000003
+#define    PPLL_REF_DIV__PPLL_REF_DIV__MASK                     0x000003FF
+#define    PPLL_REF_DIV__PPLL_REF_DIV__SHIFT                    0
+#define    PPLL_REF_DIV__PPLL_ATOMIC_UPDATE_W                   0x00008000
+#define    PPLL_REF_DIV__PPLL_ATOMIC_UPDATE_R                   0x00008000
+#define    PPLL_REF_DIV__PPLL_REF_DIV_SRC__MASK                 0x00030000
+#define    PPLL_REF_DIV__PPLL_REF_DIV_SRC__SHIFT                16
+#define    PPLL_REF_DIV_SRC__XTALIN                                 0x0
+#define    PPLL_REF_DIV_SRC__PLLSCLK_2                              0x1
+#define    PPLL_REF_DIV_SRC__PLLSCLK_4                              0x2
+#define    PPLL_REF_DIV_SRC__SREFCLK                                0x3
+#define    PPLL_REF_DIV__PPLL_REF_DIV_ACC__MASK                 0x0FFC0000
+#define    PPLL_REF_DIV__PPLL_REF_DIV_ACC__SHIFT                18
+#define PPLL_DIV_0                                          0x00000004
+#define    PPLL_DIV_0__PPLL_FB0_DIV__MASK                       0x000007FF
+#define    PPLL_DIV_0__PPLL_FB0_DIV__SHIFT                      0
+#define    PPLL_DIV_0__PPLL_ATOMIC_UPDATE_W                     0x00008000
+#define    PPLL_DIV_0__PPLL_ATOMIC_UPDATE_R                     0x00008000
+#define    PPLL_DIV_0__PPLL_POST0_DIV__MASK                     0x00070000
+#define    PPLL_DIV_0__PPLL_POST0_DIV__SHIFT                    16
+#define    PPLL_DIV_0__PPLL_FB_DIV_FRACTION__MASK               0x00380000
+#define    PPLL_DIV_0__PPLL_FB_DIV_FRACTION__SHIFT              19
+#define    PPLL_DIV_0__PPLL_FB_DIV_FRACTION_UPDATE              0x00400000
+#define    PPLL_DIV_0__PPLL_FB_DIV_FRACTION_EN                  0x00800000
+#define PPLL_DIV_1                                          0x00000005
+#define    PPLL_DIV_1__PPLL_FB1_DIV__MASK                       0x000007FF
+#define    PPLL_DIV_1__PPLL_FB1_DIV__SHIFT                      0
+#define    PPLL_DIV_1__PPLL_ATOMIC_UPDATE_W                     0x00008000
+#define    PPLL_DIV_1__PPLL_ATOMIC_UPDATE_R                     0x00008000
+#define    PPLL_DIV_1__PPLL_POST1_DIV__MASK                     0x00070000
+#define    PPLL_DIV_1__PPLL_POST1_DIV__SHIFT                    16
+#define PPLL_DIV_2                                          0x00000006
+#define    PPLL_DIV_2__PPLL_FB2_DIV__MASK                       0x000007FF
+#define    PPLL_DIV_2__PPLL_FB2_DIV__SHIFT                      0
+#define    PPLL_DIV_2__PPLL_ATOMIC_UPDATE_W                     0x00008000
+#define    PPLL_DIV_2__PPLL_ATOMIC_UPDATE_R                     0x00008000
+#define    PPLL_DIV_2__PPLL_POST2_DIV__MASK                     0x00070000
+#define    PPLL_DIV_2__PPLL_POST2_DIV__SHIFT                    16
+#define PPLL_DIV_3                                          0x00000007
+#define    PPLL_DIV_3__PPLL_FB3_DIV__MASK                       0x000007FF
+#define    PPLL_DIV_3__PPLL_FB3_DIV__SHIFT                      0
+#define    PPLL_DIV_3__PPLL_ATOMIC_UPDATE_W                     0x00008000
+#define    PPLL_DIV_3__PPLL_ATOMIC_UPDATE_R                     0x00008000
+#define    PPLL_DIV_3__PPLL_POST3_DIV__MASK                     0x00070000
+#define    PPLL_DIV_3__PPLL_POST3_DIV__SHIFT                    16
+#define VCLK_ECP_CNTL                                       0x00000008
+#define    VCLK_ECP_CNTL__VCLK_SRC_SEL__MASK                    0x00000003
+#define    VCLK_ECP_CNTL__VCLK_SRC_SEL__SHIFT                   0
+#define    VCLK_SRC_SEL__CPUCLK                                     0x0
+#define    VCLK_SRC_SEL__PSCANCLK                                   0x1
+#define    VCLK_SRC_SEL__BYTE_CLK                                   0x2
+#define    VCLK_SRC_SEL__PPLLCLK                                    0x3
+#define    VCLK_ECP_CNTL__VCLK_INVERT                           0x00000010
+#define    VCLK_ECP_CNTL__PIXCLK_ALWAYS_ONb                     0x00000040
+#define    VCLK_ECP_CNTL__PIXCLK_DAC_ALWAYS_ONb                 0x00000080
+#define    VCLK_ECP_CNTL__ECP_DIV__MASK                         0x00000300
+#define    VCLK_ECP_CNTL__ECP_DIV__SHIFT                        8
+#define    VCLK_ECP_CNTL__ECP_FORCE_ON                          0x00040000
+#define    VCLK_ECP_CNTL__SUBCLK_FORCE_ON                       0x00080000
+#define    VCLK_ECP_CNTL__BYTE_CLK_POST_DIV__MASK               0x00030000
+#define    VCLK_ECP_CNTL__BYTE_CLK_POST_DIV__SHIFT              16
+#define    VCLK_ECP_CNTL__BYTE_CLK_OUT_EN                       0x00100000
+#define    VCLK_ECP_CNTL__BYTE_CLK_SKEW__MASK                   0x07000000
+#define    VCLK_ECP_CNTL__BYTE_CLK_SKEW__SHIFT                  24
+#define    VCLK_ECP_CNTL__PCICLK_INVERT                         0x00000020
+#define    VCLK_ECP_CNTL__PIXCLK_SRC_INVERT                     0x00000020
+#define    VCLK_ECP_CNTL__PIXCLK_SRC_INVERT_R3                  0x08000000
+#define    VCLK_ECP_CNTL__DISP_DAC_PIXCLK_DAC_BLANK_OFF         0x00800000
+#define HTOTAL_CNTL                                         0x00000009
+#define    HTOTAL_CNTL__HTOT_PIX_SLIP__MASK                     0x0000000F
+#define    HTOTAL_CNTL__HTOT_PIX_SLIP__SHIFT                    0
+#define    HTOTAL_CNTL__HTOT_VCLK_SLIP__MASK                    0x00000F00
+#define    HTOTAL_CNTL__HTOT_VCLK_SLIP__SHIFT                   8
+#define    HTOTAL_CNTL__HTOT_PPLL_SLIP__MASK                    0x00070000
+#define    HTOTAL_CNTL__HTOT_PPLL_SLIP__SHIFT                   16
+#define    HTOTAL_CNTL__HTOT_CNTL_EDGE                          0x01000000
+#define    HTOTAL_CNTL__HTOT_CNTL_VGA_EN                        0x10000000
+#define FP_H_SYNC_STRT_WID                                  0x000002C4
+#define    FP_H_SYNC_STRT_WID__FP_H_SYNC_STRT_PIX__MASK         0x00000007
+#define    FP_H_SYNC_STRT_WID__FP_H_SYNC_STRT_PIX__SHIFT        0
+#define    FP_H_SYNC_STRT_WID__FP_H_SYNC_STRT_CHAR__MASK        0x00001FF8
+#define    FP_H_SYNC_STRT_WID__FP_H_SYNC_STRT_CHAR__SHIFT       3
+#define    FP_H_SYNC_STRT_WID__FP_H_SYNC_WID__MASK              0x003F0000
+#define    FP_H_SYNC_STRT_WID__FP_H_SYNC_WID__SHIFT             16
+#define    FP_H_SYNC_STRT_WID__FP_H_SYNC_POL                    0x00800000
+#define FP_V_SYNC_STRT_WID                                  0x000002C8
+#define    FP_V_SYNC_STRT_WID__FP_V_SYNC_STRT__MASK             0x00000FFF
+#define    FP_V_SYNC_STRT_WID__FP_V_SYNC_STRT__SHIFT            0
+#define    FP_V_SYNC_STRT_WID__FP_V_SYNC_WID__MASK              0x001F0000
+#define    FP_V_SYNC_STRT_WID__FP_V_SYNC_WID__SHIFT             16
+#define    FP_V_SYNC_STRT_WID__FP_V_SYNC_POL                    0x00800000
+#define FP_CRTC_H_TOTAL_DISP                                0x00000250
+#define    FP_CRTC_H_TOTAL_DISP__FP_CRTC_H_TOTAL__MASK          0x000003FF
+#define    FP_CRTC_H_TOTAL_DISP__FP_CRTC_H_TOTAL__SHIFT         0
+#define    FP_CRTC_H_TOTAL_DISP__FP_CRTC_H_DISP__MASK           0x01FF0000
+#define    FP_CRTC_H_TOTAL_DISP__FP_CRTC_H_DISP__SHIFT          16
+#define FP_CRTC_V_TOTAL_DISP                                0x00000254
+#define    FP_CRTC_V_TOTAL_DISP__FP_CRTC_V_TOTAL__MASK          0x00000FFF
+#define    FP_CRTC_V_TOTAL_DISP__FP_CRTC_V_TOTAL__SHIFT         0
+#define    FP_CRTC_V_TOTAL_DISP__FP_CRTC_V_DISP__MASK           0x0FFF0000
+#define    FP_CRTC_V_TOTAL_DISP__FP_CRTC_V_DISP__SHIFT          16
+#define PALETTE_INDEX                                       0x000000B0
+#define    PALETTE_INDEX__PALETTE_W_INDEX__MASK                 0x000000FF
+#define    PALETTE_INDEX__PALETTE_W_INDEX__SHIFT                0
+#define    PALETTE_INDEX__PALETTE_R_INDEX__MASK                 0x00FF0000
+#define    PALETTE_INDEX__PALETTE_R_INDEX__SHIFT                16
+#define PALETTE_DATA                                        0x000000B4
+#define    PALETTE_DATA__PALETTE_DATA_B__MASK                   0x000000FF
+#define    PALETTE_DATA__PALETTE_DATA_B__SHIFT                  0
+#define    PALETTE_DATA__PALETTE_DATA_G__MASK                   0x0000FF00
+#define    PALETTE_DATA__PALETTE_DATA_G__SHIFT                  8
+#define    PALETTE_DATA__PALETTE_DATA_R__MASK                   0x00FF0000
+#define    PALETTE_DATA__PALETTE_DATA_R__SHIFT                  16
+#define PALETTE_30_DATA                                     0x000000B8
+#define    PALETTE_30_DATA__PALETTE_DATA_B__MASK                0x000003FF
+#define    PALETTE_30_DATA__PALETTE_DATA_B__SHIFT               0
+#define    PALETTE_30_DATA__PALETTE_DATA_G__MASK                0x000FFC00
+#define    PALETTE_30_DATA__PALETTE_DATA_G__SHIFT               10
+#define    PALETTE_30_DATA__PALETTE_DATA_R__MASK                0x3FF00000
+#define    PALETTE_30_DATA__PALETTE_DATA_R__SHIFT               20
+#define SURFACE_CNTL                                        0x00000B00
+#define    SURFACE_CNTL__SURF_TRANSLATION_DIS                   0x00000100
+#define    SURFACE_CNTL__NONSURF_AP0_SWP__MASK                  0x00300000
+#define    SURFACE_CNTL__NONSURF_AP0_SWP__SHIFT                 20
+#define    SURFACE_CNTL__NONSURF_AP1_SWP__MASK                  0x00C00000
+#define    SURFACE_CNTL__NONSURF_AP1_SWP__SHIFT                 22
+#define SURFACE0_INFO                                       0x00000B0C
+#define    SURFACE0_INFO__SURF0_PITCHSEL__MASK                  0x000003FF
+#define    SURFACE0_INFO__SURF0_PITCHSEL__SHIFT                 0
+#define    SURFACE0_INFO__SURF0_TILE_MODE__MASK                 0x00030000
+#define    SURFACE0_INFO__SURF0_TILE_MODE__SHIFT                16
+#define    SURF0_TILE_MODE__NO_TILING(p)                            0x0
+#define    SURF0_TILE_MODE__MACRO_TILING(p)                         0x0
+#define    SURF0_TILE_MODE__MICRO_TILING(p)                         0x0
+#define    SURF0_TILE_MODE__MACRO_MICRO_TILING(p)                   0x0
+#define    SURF0_TILE_MODE__32_BIT_Z_TILING(p)                      0x0
+#define    SURF0_TILE_MODE__16_BIT_Z_TILING(p)                      0x0
+#define    SURFACE0_INFO__SURF0_AP0_SWP__MASK                   0x00300000
+#define    SURFACE0_INFO__SURF0_AP0_SWP__SHIFT                  20
+#define    SURFACE0_INFO__SURF0_AP1_SWP__MASK                   0x00C00000
+#define    SURFACE0_INFO__SURF0_AP1_SWP__SHIFT                  22
+#define    SURFACE0_INFO__SURF0_WRITE_FLAG                      0x01000000
+#define    SURFACE0_INFO__SURF0_READ_FLAG                       0x02000000
+#define    SURFACE0_INFO__SURF0_TILE_MODE_R2__MASK              0x00070000
+#define    SURFACE0_INFO__SURF0_TILE_MODE_R2__SHIFT             16
+#define    SURFACE0_INFO__SURF0_PITCHSEL_R3__MASK               0x00001FFF
+#define    SURFACE0_INFO__SURF0_PITCHSEL_R3__SHIFT              0
+#define SURFACE0_LOWER_BOUND                                0x00000B04
+#define    SURFACE0_LOWER_BOUND__SURF_LOWER__MASK               0x0FFFFFFF
+#define    SURFACE0_LOWER_BOUND__SURF_LOWER__SHIFT              0
+#define SURFACE0_UPPER_BOUND                                0x00000B08
+#define    SURFACE0_UPPER_BOUND__SURF_UPPER__MASK               0x0FFFFFFF
+#define    SURFACE0_UPPER_BOUND__SURF_UPPER__SHIFT              0
+#define SURFACE1_INFO                                       0x00000B1C
+#define    SURFACE1_INFO__SURF1_PITCHSEL__MASK                  0x000003FF
+#define    SURFACE1_INFO__SURF1_PITCHSEL__SHIFT                 0
+#define    SURFACE1_INFO__SURF1_TILE_MODE__MASK                 0x00030000
+#define    SURFACE1_INFO__SURF1_TILE_MODE__SHIFT                16
+#define    SURFACE1_INFO__SURF1_AP0_SWP__MASK                   0x00300000
+#define    SURFACE1_INFO__SURF1_AP0_SWP__SHIFT                  20
+#define    SURFACE1_INFO__SURF1_AP1_SWP__MASK                   0x00C00000
+#define    SURFACE1_INFO__SURF1_AP1_SWP__SHIFT                  22
+#define    SURFACE1_INFO__SURF1_WRITE_FLAG                      0x01000000
+#define    SURFACE1_INFO__SURF1_READ_FLAG                       0x02000000
+#define    SURFACE1_INFO__SURF1_TILE_MODE_R2__MASK              0x00070000
+#define    SURFACE1_INFO__SURF1_TILE_MODE_R2__SHIFT             16
+#define    SURFACE1_INFO__SURF1_PITCHSEL_R3__MASK               0x00001FFF
+#define    SURFACE1_INFO__SURF1_PITCHSEL_R3__SHIFT              0
+#define SURFACE1_LOWER_BOUND                                0x00000B14
+#define    SURFACE1_LOWER_BOUND__SURF_LOWER__MASK               0x0FFFFFFF
+#define    SURFACE1_LOWER_BOUND__SURF_LOWER__SHIFT              0
+#define SURFACE1_UPPER_BOUND                                0x00000B18
+#define    SURFACE1_UPPER_BOUND__SURF_UPPER__MASK               0x0FFFFFFF
+#define    SURFACE1_UPPER_BOUND__SURF_UPPER__SHIFT              0
+#define SURFACE2_INFO                                       0x00000B2C
+#define    SURFACE2_INFO__SURF2_PITCHSEL__MASK                  0x000003FF
+#define    SURFACE2_INFO__SURF2_PITCHSEL__SHIFT                 0
+#define    SURFACE2_INFO__SURF2_TILE_MODE__MASK                 0x00030000
+#define    SURFACE2_INFO__SURF2_TILE_MODE__SHIFT                16
+#define    SURFACE2_INFO__SURF2_AP0_SWP__MASK                   0x00300000
+#define    SURFACE2_INFO__SURF2_AP0_SWP__SHIFT                  20
+#define    SURFACE2_INFO__SURF2_AP1_SWP__MASK                   0x00C00000
+#define    SURFACE2_INFO__SURF2_AP1_SWP__SHIFT                  22
+#define    SURFACE2_INFO__SURF2_WRITE_FLAG                      0x01000000
+#define    SURFACE2_INFO__SURF2_READ_FLAG                       0x02000000
+#define    SURFACE2_INFO__SURF2_TILE_MODE_R2__MASK              0x00070000
+#define    SURFACE2_INFO__SURF2_TILE_MODE_R2__SHIFT             16
+#define    SURFACE2_INFO__SURF2_PITCHSEL_R3__MASK               0x00001FFF
+#define    SURFACE2_INFO__SURF2_PITCHSEL_R3__SHIFT              0
+#define SURFACE2_LOWER_BOUND                                0x00000B24
+#define    SURFACE2_LOWER_BOUND__SURF_LOWER__MASK               0x0FFFFFFF
+#define    SURFACE2_LOWER_BOUND__SURF_LOWER__SHIFT              0
+#define SURFACE2_UPPER_BOUND                                0x00000B28
+#define    SURFACE2_UPPER_BOUND__SURF_UPPER__MASK               0x0FFFFFFF
+#define    SURFACE2_UPPER_BOUND__SURF_UPPER__SHIFT              0
+#define SURFACE3_INFO                                       0x00000B3C
+#define    SURFACE3_INFO__SURF3_PITCHSEL__MASK                  0x000003FF
+#define    SURFACE3_INFO__SURF3_PITCHSEL__SHIFT                 0
+#define    SURFACE3_INFO__SURF3_TILE_MODE__MASK                 0x00030000
+#define    SURFACE3_INFO__SURF3_TILE_MODE__SHIFT                16
+#define    SURFACE3_INFO__SURF3_AP0_SWP__MASK                   0x00300000
+#define    SURFACE3_INFO__SURF3_AP0_SWP__SHIFT                  20
+#define    SURFACE3_INFO__SURF3_AP1_SWP__MASK                   0x00C00000
+#define    SURFACE3_INFO__SURF3_AP1_SWP__SHIFT                  22
+#define    SURFACE3_INFO__SURF3_WRITE_FLAG                      0x01000000
+#define    SURFACE3_INFO__SURF3_READ_FLAG                       0x02000000
+#define    SURFACE3_INFO__SURF3_TILE_MODE_R2__MASK              0x00070000
+#define    SURFACE3_INFO__SURF3_TILE_MODE_R2__SHIFT             16
+#define    SURFACE3_INFO__SURF3_PITCHSEL_R3__MASK               0x00001FFF
+#define    SURFACE3_INFO__SURF3_PITCHSEL_R3__SHIFT              0
+#define SURFACE3_LOWER_BOUND                                0x00000B34
+#define    SURFACE3_LOWER_BOUND__SURF_LOWER__MASK               0x0FFFFFFF
+#define    SURFACE3_LOWER_BOUND__SURF_LOWER__SHIFT              0
+#define SURFACE3_UPPER_BOUND                                0x00000B38
+#define    SURFACE3_UPPER_BOUND__SURF_UPPER__MASK               0x0FFFFFFF
+#define    SURFACE3_UPPER_BOUND__SURF_UPPER__SHIFT              0
+#define SURFACE4_INFO                                       0x00000B4C
+#define    SURFACE4_INFO__SURF4_PITCHSEL__MASK                  0x000003FF
+#define    SURFACE4_INFO__SURF4_PITCHSEL__SHIFT                 0
+#define    SURFACE4_INFO__SURF4_TILE_MODE__MASK                 0x00030000
+#define    SURFACE4_INFO__SURF4_TILE_MODE__SHIFT                16
+#define    SURFACE4_INFO__SURF4_AP0_SWP__MASK                   0x00300000
+#define    SURFACE4_INFO__SURF4_AP0_SWP__SHIFT                  20
+#define    SURFACE4_INFO__SURF4_AP1_SWP__MASK                   0x00C00000
+#define    SURFACE4_INFO__SURF4_AP1_SWP__SHIFT                  22
+#define    SURFACE4_INFO__SURF4_WRITE_FLAG                      0x01000000
+#define    SURFACE4_INFO__SURF4_READ_FLAG                       0x02000000
+#define    SURFACE4_INFO__SURF4_TILE_MODE_R2__MASK              0x00070000
+#define    SURFACE4_INFO__SURF4_TILE_MODE_R2__SHIFT             16
+#define    SURFACE4_INFO__SURF4_PITCHSEL_R3__MASK               0x00001FFF
+#define    SURFACE4_INFO__SURF4_PITCHSEL_R3__SHIFT              0
+#define SURFACE4_LOWER_BOUND                                0x00000B44
+#define    SURFACE4_LOWER_BOUND__SURF_LOWER__MASK               0x0FFFFFFF
+#define    SURFACE4_LOWER_BOUND__SURF_LOWER__SHIFT              0
+#define SURFACE4_UPPER_BOUND                                0x00000B48
+#define    SURFACE4_UPPER_BOUND__SURF_UPPER__MASK               0x0FFFFFFF
+#define    SURFACE4_UPPER_BOUND__SURF_UPPER__SHIFT              0
+#define SURFACE5_INFO                                       0x00000B5C
+#define    SURFACE5_INFO__SURF5_PITCHSEL__MASK                  0x000003FF
+#define    SURFACE5_INFO__SURF5_PITCHSEL__SHIFT                 0
+#define    SURFACE5_INFO__SURF5_TILE_MODE__MASK                 0x00030000
+#define    SURFACE5_INFO__SURF5_TILE_MODE__SHIFT                16
+#define    SURFACE5_INFO__SURF5_AP0_SWP__MASK                   0x00300000
+#define    SURFACE5_INFO__SURF5_AP0_SWP__SHIFT                  20
+#define    SURFACE5_INFO__SURF5_AP1_SWP__MASK                   0x00C00000
+#define    SURFACE5_INFO__SURF5_AP1_SWP__SHIFT                  22
+#define    SURFACE5_INFO__SURF5_WRITE_FLAG                      0x01000000
+#define    SURFACE5_INFO__SURF5_READ_FLAG                       0x02000000
+#define    SURFACE5_INFO__SURF5_TILE_MODE_R2__MASK              0x00070000
+#define    SURFACE5_INFO__SURF5_TILE_MODE_R2__SHIFT             16
+#define    SURFACE5_INFO__SURF5_PITCHSEL_R3__MASK               0x00001FFF
+#define    SURFACE5_INFO__SURF5_PITCHSEL_R3__SHIFT              0
+#define SURFACE5_LOWER_BOUND                                0x00000B54
+#define    SURFACE5_LOWER_BOUND__SURF_LOWER__MASK               0x0FFFFFFF
+#define    SURFACE5_LOWER_BOUND__SURF_LOWER__SHIFT              0
+#define SURFACE5_UPPER_BOUND                                0x00000B58
+#define    SURFACE5_UPPER_BOUND__SURF_UPPER__MASK               0x0FFFFFFF
+#define    SURFACE5_UPPER_BOUND__SURF_UPPER__SHIFT              0
+#define SURFACE6_INFO                                       0x00000B6C
+#define    SURFACE6_INFO__SURF6_PITCHSEL__MASK                  0x000003FF
+#define    SURFACE6_INFO__SURF6_PITCHSEL__SHIFT                 0
+#define    SURFACE6_INFO__SURF6_TILE_MODE__MASK                 0x00030000
+#define    SURFACE6_INFO__SURF6_TILE_MODE__SHIFT                16
+#define    SURFACE6_INFO__SURF6_AP0_SWP__MASK                   0x00300000
+#define    SURFACE6_INFO__SURF6_AP0_SWP__SHIFT                  20
+#define    SURFACE6_INFO__SURF6_AP1_SWP__MASK                   0x00C00000
+#define    SURFACE6_INFO__SURF6_AP1_SWP__SHIFT                  22
+#define    SURFACE6_INFO__SURF6_WRITE_FLAG                      0x01000000
+#define    SURFACE6_INFO__SURF6_READ_FLAG                       0x02000000
+#define    SURFACE6_INFO__SURF6_TILE_MODE_R2__MASK              0x00070000
+#define    SURFACE6_INFO__SURF6_TILE_MODE_R2__SHIFT             16
+#define    SURFACE6_INFO__SURF6_PITCHSEL_R3__MASK               0x00001FFF
+#define    SURFACE6_INFO__SURF6_PITCHSEL_R3__SHIFT              0
+#define SURFACE6_LOWER_BOUND                                0x00000B64
+#define    SURFACE6_LOWER_BOUND__SURF_LOWER__MASK               0x0FFFFFFF
+#define    SURFACE6_LOWER_BOUND__SURF_LOWER__SHIFT              0
+#define SURFACE6_UPPER_BOUND                                0x00000B68
+#define    SURFACE6_UPPER_BOUND__SURF_UPPER__MASK               0x0FFFFFFF
+#define    SURFACE6_UPPER_BOUND__SURF_UPPER__SHIFT              0
+#define SURFACE7_INFO                                       0x00000B7C
+#define    SURFACE7_INFO__SURF7_PITCHSEL__MASK                  0x000003FF
+#define    SURFACE7_INFO__SURF7_PITCHSEL__SHIFT                 0
+#define    SURFACE7_INFO__SURF7_TILE_MODE__MASK                 0x00030000
+#define    SURFACE7_INFO__SURF7_TILE_MODE__SHIFT                16
+#define    SURFACE7_INFO__SURF7_AP0_SWP__MASK                   0x00300000
+#define    SURFACE7_INFO__SURF7_AP0_SWP__SHIFT                  20
+#define    SURFACE7_INFO__SURF7_AP1_SWP__MASK                   0x00C00000
+#define    SURFACE7_INFO__SURF7_AP1_SWP__SHIFT                  22
+#define    SURFACE7_INFO__SURF7_WRITE_FLAG                      0x01000000
+#define    SURFACE7_INFO__SURF7_READ_FLAG                       0x02000000
+#define    SURFACE7_INFO__SURF7_TILE_MODE_R2__MASK              0x00070000
+#define    SURFACE7_INFO__SURF7_TILE_MODE_R2__SHIFT             16
+#define    SURFACE7_INFO__SURF7_PITCHSEL_R3__MASK               0x00001FFF
+#define    SURFACE7_INFO__SURF7_PITCHSEL_R3__SHIFT              0
+#define SURFACE7_LOWER_BOUND                                0x00000B74
+#define    SURFACE7_LOWER_BOUND__SURF_LOWER__MASK               0x0FFFFFFF
+#define    SURFACE7_LOWER_BOUND__SURF_LOWER__SHIFT              0
+#define SURFACE7_UPPER_BOUND                                0x00000B78
+#define    SURFACE7_UPPER_BOUND__SURF_UPPER__MASK               0x0FFFFFFF
+#define    SURFACE7_UPPER_BOUND__SURF_UPPER__SHIFT              0
+#define ISYNC_CNTL                                          0x00001724
+#define    ISYNC_CNTL__ISYNC_ANY2D_IDLE3D                       0x00000001
+#define    ISYNC_CNTL__ISYNC_ANY3D_IDLE2D                       0x00000002
+#define    ISYNC_CNTL__ISYNC_TRIG2D_IDLE3D                      0x00000004
+#define    ISYNC_CNTL__ISYNC_TRIG3D_IDLE2D                      0x00000008
+#define    ISYNC_CNTL__ISYNC_WAIT_IDLEGUI                       0x00000010
+#define    ISYNC_CNTL__ISYNC_CPSCRATCH_IDLEGUI                  0x00000020
+#define RBBM_STATUS                                         0x00000E40
+#define    RBBM_STATUS__CMDFIFO_AVAIL__MASK                     0x0000007F
+#define    RBBM_STATUS__CMDFIFO_AVAIL__SHIFT                    0
+#define    RBBM_STATUS__HIRQ_ON_RBB                             0x00000100
+#define    RBBM_STATUS__CPRQ_ON_RBB                             0x00000200
+#define    RBBM_STATUS__CFRQ_ON_RBB                             0x00000400
+#define    RBBM_STATUS__HIRQ_IN_RTBUF                           0x00000800
+#define    RBBM_STATUS__CPRQ_IN_RTBUF                           0x00001000
+#define    RBBM_STATUS__CFRQ_IN_RTBUF                           0x00002000
+#define    RBBM_STATUS__CF_PIPE_BUSY                            0x00004000
+#define    RBBM_STATUS__ENG_EV_BUSY                             0x00008000
+#define    RBBM_STATUS__CP_CMDSTRM_BUSY                         0x00010000
+#define    RBBM_STATUS__E2_BUSY                                 0x00020000
+#define    RBBM_STATUS__RB2D_BUSY                               0x00040000
+#define    RBBM_STATUS__RB3D_BUSY                               0x00080000
+#define    RBBM_STATUS__SE_BUSY                                 0x00100000
+#define    RBBM_STATUS__RE_BUSY                                 0x00200000
+#define    RBBM_STATUS__TAM_BUSY                                0x00400000
+#define    RBBM_STATUS__TDM_BUSY                                0x00800000
+#define    RBBM_STATUS__PB_BUSY                                 0x01000000
+#define    RBBM_STATUS__GUI_ACTIVE                              0x80000000
+#define    RBBM_STATUS__VAP_BUSY                                0x00100000
+#define    RBBM_STATUS__TIM_BUSY                                0x02000000
+#define    RBBM_STATUS__GA_BUSY                                 0x04000000
+#define    RBBM_STATUS__CBA2D_BUSY                              0x08000000
+#define RBBM_SOFT_RESET                                     0x000000F0
+#define    RBBM_SOFT_RESET__SOFT_RESET_CP                       0x00000001
+#define    RBBM_SOFT_RESET__SOFT_RESET_HI                       0x00000002
+#define    RBBM_SOFT_RESET__SOFT_RESET_SE                       0x00000004
+#define    RBBM_SOFT_RESET__SOFT_RESET_RE                       0x00000008
+#define    RBBM_SOFT_RESET__SOFT_RESET_PP                       0x00000010
+#define    RBBM_SOFT_RESET__SOFT_RESET_E2                       0x00000020
+#define    RBBM_SOFT_RESET__SOFT_RESET_RB                       0x00000040
+#define    RBBM_SOFT_RESET__SOFT_RESET_HDP                      0x00000080
+#define    RBBM_SOFT_RESET__SOFT_RESET_MC                       0x00000100
+#define    RBBM_SOFT_RESET__SOFT_RESET_AIC                      0x00000200
+#define    RBBM_SOFT_RESET__SOFT_RESET_VIP                      0x00000400
+#define    RBBM_SOFT_RESET__SOFT_RESET_DISP                     0x00000800
+#define    RBBM_SOFT_RESET__SOFT_RESET_CG                       0x00001000
+#define    RBBM_SOFT_RESET__SOFT_RESET_VAP                      0x00000004
+#define    RBBM_SOFT_RESET__SOFT_RESET_GA                       0x00002000
+#define    RBBM_SOFT_RESET__SOFT_RESET_IDCT                     0x00004000
+#define WAIT_UNTIL                                          0x00001720
+#define    WAIT_UNTIL__WAIT_CRTC_PFLIP                          0x00000001
+#define    WAIT_UNTIL__WAIT_RE_CRTC_VLINE                       0x00000002
+#define    WAIT_UNTIL__WAIT_FE_CRTC_VLINE                       0x00000004
+#define    WAIT_UNTIL__WAIT_CRTC_VLINE                          0x00000008
+#define    WAIT_UNTIL__WAIT_DMA_VIPH0_IDLE                      0x00000010
+#define    WAIT_UNTIL__WAIT_DMA_VIPH1_IDLE                      0x00000020
+#define    WAIT_UNTIL__WAIT_DMA_VIPH2_IDLE                      0x00000040
+#define    WAIT_UNTIL__WAIT_DMA_VIPH3_IDLE                      0x00000080
+#define    WAIT_UNTIL__WAIT_DMA_VID_IDLE                        0x00000100
+#define    WAIT_UNTIL__WAIT_DMA_GUI_IDLE                        0x00000200
+#define    WAIT_UNTIL__WAIT_CMDFIFO                             0x00000400
+#define    WAIT_UNTIL__WAIT_OV0_FLIP                            0x00000800
+#define    WAIT_UNTIL__WAIT_OV0_SLICEDONE                       0x00001000
+#define    WAIT_UNTIL__WAIT_2D_IDLE                             0x00004000
+#define    WAIT_UNTIL__WAIT_3D_IDLE                             0x00008000
+#define    WAIT_UNTIL__WAIT_2D_IDLECLEAN                        0x00010000
+#define    WAIT_UNTIL__WAIT_3D_IDLECLEAN                        0x00020000
+#define    WAIT_UNTIL__WAIT_HOST_IDLECLEAN                      0x00040000
+#define    WAIT_UNTIL__WAIT_EXTERN_SIG                          0x00080000
+#define    WAIT_UNTIL__CMDFIFO_ENTRIES__MASK                    0x07F00000
+#define    WAIT_UNTIL__CMDFIFO_ENTRIES__SHIFT                   20
+#define    WAIT_UNTIL__WAIT_BOTH_CRTC_PFLIP                     0x40000000
+#define    WAIT_UNTIL__ENG_DISPLAY_SELECT                       0x80000000
+#define    WAIT_UNTIL__WAIT_AGP_FLUSH                           0x00002000
+#define    WAIT_UNTIL__WAIT_IDCT_SEMAPHORE                      0x08000000
+#define    WAIT_UNTIL__WAIT_VAP_IDLE                            0x10000000
+#define DISPLAY_BASE_ADDR                                   0x0000023C
+#define    DISPLAY_BASE_ADDR__DISPLAY_BASE_ADDR__MASK           0xFFFFFFFF
+#define    DISPLAY_BASE_ADDR__DISPLAY_BASE_ADDR__SHIFT          0
+#define CRTC2_DISPLAY_BASE_ADDR                             0x0000033C
+#define    CRTC2_DISPLAY_BASE_ADDR__CRTC2_DISPLAY_BASE_ADDR__MASK 0xFFFFFFFF
+#define    CRTC2_DISPLAY_BASE_ADDR__CRTC2_DISPLAY_BASE_ADDR__SHIFT 0
+#define AIC_CTRL                                            0x000001D0
+#define    AIC_CTRL__TRANSLATE_EN                               0x00000001
+#define    AIC_CTRL__HW_0_DEBUG                                 0x00000002
+#define    AIC_CTRL__HW_1_DEBUG                                 0x00000004
+#define    AIC_CTRL__HW_2_DEBUG                                 0x00000008
+#define    AIC_CTRL__HW_3_DEBUG                                 0x00000010
+#define    AIC_CTRL__HW_4_DEBUG                                 0x00000020
+#define    AIC_CTRL__HW_5_DEBUG                                 0x00000040
+#define    AIC_CTRL__HW_6_DEBUG                                 0x00000080
+#define    AIC_CTRL__HW_7_DEBUG                                 0x00000100
+#define    AIC_CTRL__HW_8_DEBUG                                 0x00000200
+#define    AIC_CTRL__HW_9_DEBUG                                 0x00000400
+#define    AIC_CTRL__HW_A_DEBUG                                 0x00000800
+#define    AIC_CTRL__HW_B_DEBUG                                 0x00001000
+#define    AIC_CTRL__HW_C_DEBUG                                 0x00002000
+#define    AIC_CTRL__HW_D_DEBUG                                 0x00004000
+#define    AIC_CTRL__HW_E_DEBUG                                 0x00008000
+#define    AIC_CTRL__HW_F_DEBUG                                 0x00010000
+#define    AIC_CTRL__HW_10_DEBUG                                0x00020000
+#define    AIC_CTRL__HW_11_DEBUG                                0x00040000
+#define    AIC_CTRL__HW_12_DEBUG                                0x00080000
+#define    AIC_CTRL__HW_13_DEBUG                                0x00100000
+#define    AIC_CTRL__HW_14_DEBUG                                0x00200000
+#define    AIC_CTRL__HW_15_DEBUG                                0x00400000
+#define    AIC_CTRL__HW_16_DEBUG                                0x00800000
+#define    AIC_CTRL__HW_17_DEBUG                                0x01000000
+#define    AIC_CTRL__HW_18_DEBUG                                0x02000000
+#define    AIC_CTRL__HW_19_DEBUG                                0x04000000
+#define    AIC_CTRL__HW_1A_DEBUG                                0x08000000
+#define    AIC_CTRL__HW_1B_DEBUG                                0x10000000
+#define    AIC_CTRL__HW_1C_DEBUG                                0x20000000
+#define    AIC_CTRL__HW_1D_DEBUG                                0x40000000
+#define    AIC_CTRL__HW_1E_DEBUG                                0x80000000
+#define    AIC_CTRL__DIS_OUT_OF_PCI_GART_ACCESS                 0x00000002
+#define    AIC_CTRL__HW_02_DEBUG                                0x00000004
+#define    AIC_CTRL__HW_03_DEBUG                                0x00000008
+#define    AIC_CTRL__TEST_RBF_DIV_VAL__MASK                     0x00000070
+#define    AIC_CTRL__TEST_RBF_DIV_VAL__SHIFT                    4
+#define    AIC_CTRL__TEST_RBF_EN                                0x00000080
+#define    AIC_CTRL__HW_08_DEBUG                                0x00000100
+#define    AIC_CTRL__HW_09_DEBUG                                0x00000200
+#define    AIC_CTRL__HW_10_DEBUG_R3                             0x00000400
+#define    AIC_CTRL__HW_11_DEBUG_R3                             0x00000800
+#define    AIC_CTRL__HW_12_DEBUG_R3                             0x00001000
+#define    AIC_CTRL__HW_13_DEBUG_R3                             0x00002000
+#define    AIC_CTRL__HW_14_DEBUG_R3                             0x00004000
+#define    AIC_CTRL__HW_15_DEBUG_R3                             0x00008000
+#define    AIC_CTRL__HW_16_DEBUG_R3                             0x00010000
+#define    AIC_CTRL__HW_17_DEBUG_R3                             0x00020000
+#define    AIC_CTRL__HW_18_DEBUG_R3                             0x00040000
+#define    AIC_CTRL__HW_19_DEBUG_R3                             0x00080000
+#define    AIC_CTRL__HW_20_DEBUG                                0x00100000
+#define    AIC_CTRL__HW_21_DEBUG                                0x00200000
+#define    AIC_CTRL__HW_22_DEBUG                                0x00400000
+#define    AIC_CTRL__HW_23_DEBUG                                0x00800000
+#define    AIC_CTRL__HW_24_DEBUG                                0x01000000
+#define    AIC_CTRL__HW_25_DEBUG                                0x02000000
+#define    AIC_CTRL__HW_26_DEBUG                                0x04000000
+#define    AIC_CTRL__HW_27_DEBUG                                0x08000000
+#define    AIC_CTRL__HW_28_DEBUG                                0x10000000
+#define    AIC_CTRL__HW_29_DEBUG                                0x20000000
+#define    AIC_CTRL__HW_30_DEBUG                                0x40000000
+#define    AIC_CTRL__HW_31_DEBUG                                0x80000000
+#define BUS_CNTL                                            0x00000030
+#define    BUS_CNTL__BUS_DBL_RESYNC                             0x00000001
+#define    BUS_CNTL__BUS_MSTR_RESET                             0x00000002
+#define    BUS_CNTL__BUS_FLUSH_BUF                              0x00000004
+#define    BUS_CNTL__BUS_STOP_REQ_DIS                           0x00000008
+#define    BUS_CNTL__BUS_READ_COMBINE_EN                        0x00000010
+#define    BUS_CNTL__BUS_WRT_COMBINE_EN                         0x00000020
+#define    BUS_CNTL__BUS_MASTER_DIS                             0x00000040
+#define    BUS_CNTL__BIOS_ROM_WRT_EN                            0x00000080
+#define    BUS_CNTL__BUS_PREFETCH_MODE__MASK                    0x00000300
+#define    BUS_CNTL__BUS_PREFETCH_MODE__SHIFT                   8
+#define    BUS_CNTL__BUS_VGA_PREFETCH_EN                        0x00000400
+#define    BUS_CNTL__BUS_SGL_READ_DISABLE                       0x00000800
+#define    BUS_CNTL__BIOS_DIS_ROM                               0x00001000
+#define    BUS_CNTL__BUS_PCI_READ_RETRY_EN                      0x00002000
+#define    BUS_CNTL__BUS_AGP_AD_STEPPING_EN                     0x00004000
+#define    BUS_CNTL__BUS_PCI_WRT_RETRY_EN                       0x00008000
+#define    BUS_CNTL__BUS_RETRY_WS__MASK                         0x000F0000
+#define    BUS_CNTL__BUS_RETRY_WS__SHIFT                        16
+#define    BUS_CNTL__BUS_MSTR_RD_MULT                           0x00100000
+#define    BUS_CNTL__BUS_MSTR_RD_LINE                           0x00200000
+#define    BUS_CNTL__BUS_SUSPEND                                0x00400000
+#define    BUS_CNTL__LAT_16X                                    0x00800000
+#define    BUS_CNTL__BUS_RD_DISCARD_EN                          0x01000000
+#define    BUS_CNTL__ENFRCWRDY                                  0x02000000
+#define    BUS_CNTL__BUS_MSTR_WS                                0x04000000
+#define    BUS_CNTL__BUS_PARKING_DIS                            0x08000000
+#define    BUS_CNTL__BUS_MSTR_DISCONNECT_EN                     0x10000000
+#define    BUS_CNTL__SERR_EN                                    0x20000000
+#define    BUS_CNTL__BUS_READ_BURST                             0x40000000
+#define    BUS_CNTL__BUS_RDY_READ_DLY                           0x80000000
+#define    BUS_CNTL__BUS_PM4_READ_COMBINE_EN                    0x00000010
+#define    BUS_CNTL__BM_DAC_CRIPPLE                             0x00000100
+#define    BUS_CNTL__BUS_NON_PM4_READ_COMBINE_EN                0x00000200
+#define    BUS_CNTL__BUS_XFERD_DISCARD_EN                       0x00000400
+#define MC_STATUS                                           0x00000150
+#define    MC_STATUS__MEM_PWRUP_COMPL_A                         0x00000001
+#define    MC_STATUS__MEM_PWRUP_COMPL_B                         0x00000002
+#define    MC_STATUS__MC_IDLE                                   0x00000004
+#define    MC_STATUS__SPARE__MASK                               0x0000FFF8
+#define    MC_STATUS__SPARE__SHIFT                              3
+#define    MC_STATUS__IMP_N_VALUE_R_BACK__MASK                  0x00000078
+#define    MC_STATUS__IMP_N_VALUE_R_BACK__SHIFT                 3
+#define    MC_STATUS__IMP_P_VALUE_R_BACK__MASK                  0x00000780
+#define    MC_STATUS__IMP_P_VALUE_R_BACK__SHIFT                 7
+#define    MC_STATUS__TEST_OUT_R_BACK                           0x00000800
+#define    MC_STATUS__DUMMY_OUT_R_BACK                          0x00001000
+#define    MC_STATUS__IMP_N_VALUE_A_R_BACK__MASK                0x0001E000
+#define    MC_STATUS__IMP_N_VALUE_A_R_BACK__SHIFT               13
+#define    MC_STATUS__IMP_P_VALUE_A_R_BACK__MASK                0x001E0000
+#define    MC_STATUS__IMP_P_VALUE_A_R_BACK__SHIFT               17
+#define    MC_STATUS__IMP_N_VALUE_CK_R_BACK__MASK               0x01E00000
+#define    MC_STATUS__IMP_N_VALUE_CK_R_BACK__SHIFT              21
+#define    MC_STATUS__IMP_P_VALUE_CK_R_BACK__MASK               0x1E000000
+#define    MC_STATUS__IMP_P_VALUE_CK_R_BACK__SHIFT              25
+#define    MC_STATUS__MEM_PWRUP_COMPL_C                         0x00000004
+#define    MC_STATUS__MEM_PWRUP_COMPL_D                         0x00000008
+#define    MC_STATUS__MC_IDLE_R3                                0x00000010
+#define    MC_STATUS__IMP_CAL_COUNT__MASK                       0x0000F000
+#define    MC_STATUS__IMP_CAL_COUNT__SHIFT                      12
+#define OV0_SCALE_CNTL                                      0x00000420
+#define    OV0_SCALE_CNTL__OV0_NO_READ_BEHIND_SCAN              0x00000002
+#define    OV0_SCALE_CNTL__OV0_HORZ_PICK_NEAREST                0x00000004
+#define    OV0_SCALE_CNTL__OV0_VERT_PICK_NEAREST                0x00000008
+#define    OV0_SCALE_CNTL__OV0_SIGNED_UV                        0x00000010
+#define    OV0_SCALE_CNTL__OV0_GAMMA_SEL__MASK                  0x000000E0
+#define    OV0_SCALE_CNTL__OV0_GAMMA_SEL__SHIFT                 5
+#define    OV0_SCALE_CNTL__OV0_SURFACE_FORMAT__MASK             0x00000F00
+#define    OV0_SCALE_CNTL__OV0_SURFACE_FORMAT__SHIFT            8
+#define    OV0_SURFACE_FORMAT__RESERVED0                            0x0
+#define    OV0_SURFACE_FORMAT__RESERVED1                            0x100
+#define    OV0_SURFACE_FORMAT__RESERVED2                            0x200
+#define    OV0_SURFACE_FORMAT__16BPP_ARGB                           0x300
+#define    OV0_SURFACE_FORMAT__16BPP_RGB                            0x400
+#define    OV0_SURFACE_FORMAT__RESERVED5                            0x500
+#define    OV0_SURFACE_FORMAT__32BPP_ARGB                           0x600
+#define    OV0_SURFACE_FORMAT__RESERVED7                            0x700
+#define    OV0_SURFACE_FORMAT__RESERVED8                            0x800
+#define    OV0_SURFACE_FORMAT__IF09_PLANAR                          0x900
+#define    OV0_SURFACE_FORMAT__YV12_PLANAR                          0xA00
+#define    OV0_SURFACE_FORMAT__YUY2_PACKED                          0xB00
+#define    OV0_SURFACE_FORMAT__UYVY_PACKED                          0xC00
+#define    OV0_SURFACE_FORMAT__YYUV9_PLANAR                         0xD00
+#define    OV0_SURFACE_FORMAT__YYUV12_PLANAR                        0xE00
+#define    OV0_SURFACE_FORMAT__RESERVED15                           0xF00
+#define    OV0_SCALE_CNTL__OV0_ADAPTIVE_DEINT                   0x00001000
+#define    OV0_SCALE_CNTL__OV0_CRTC_SEL                         0x00004000
+#define    OV0_SCALE_CNTL__OV0_BURST_PER_PLANE__MASK            0x007F0000
+#define    OV0_SCALE_CNTL__OV0_BURST_PER_PLANE__SHIFT           16
+#define    OV0_SCALE_CNTL__OV0_DOUBLE_BUFFER_REGS               0x01000000
+#define    OV0_SCALE_CNTL__OV0_BANDWIDTH                        0x04000000
+#define    OV0_SCALE_CNTL__OV0_LIN_TRANS_BYPASS                 0x10000000
+#define    OV0_SCALE_CNTL__OV0_INT_EMU                          0x20000000
+#define    OV0_SCALE_CNTL__OV0_OVERLAY_EN__MASK                 0x40000000
+#define    OV0_SCALE_CNTL__OV0_OVERLAY_EN__SHIFT                30
+#define    OV0_OVERLAY_EN__ENABLE                                   0x40000000
+#define    OV0_SCALE_CNTL__OV0_SOFT_RESET__MASK                 0x80000000
+#define    OV0_SCALE_CNTL__OV0_SOFT_RESET__SHIFT                31
+#define    OV0_SOFT_RESET__RESET                                    0x80000000
+#define    OV0_SCALE_CNTL__OV0_TEMPORAL_DEINT                   0x00002000
+#define    OV0_SCALE_CNTL__OV0_PULLDOWN_ON_P1_ONLY              0x00008000
+#define    OV0_SCALE_CNTL__OV0_FULL_BYPASS                      0x00000020
+#define    OV0_SCALE_CNTL__OV0_DYNAMIC_EXT                      0x00000040
+#define    OV0_SCALE_CNTL__OV0_RGB30_ON                         0x00000080
+#define CRTC2_GEN_CNTL                                      0x000003F8
+#define    CRTC2_GEN_CNTL__CRTC2_DBL_SCAN_EN                    0x00000001
+#define    CRTC2_GEN_CNTL__CRTC2_INTERLACE_EN                   0x00000002
+#define    CRTC2_GEN_CNTL__CRTC2_SYNC_TRISTATE                  0x00000010
+#define    CRTC2_GEN_CNTL__CRTC2_HSYNC_TRISTATE                 0x00000020
+#define    CRTC2_GEN_CNTL__CRTC2_VSYNC_TRISTATE                 0x00000040
+#define    CRTC2_GEN_CNTL__CRT2_ON                              0x00000080
+#define    CRTC2_GEN_CNTL__CRTC2_PIX_WIDTH__MASK                0x00000F00
+#define    CRTC2_GEN_CNTL__CRTC2_PIX_WIDTH__SHIFT               8
+#define    CRTC2_GEN_CNTL__CRTC2_ICON_EN                        0x00008000
+#define    CRTC2_GEN_CNTL__CRTC2_CUR_EN                         0x00010000
+#define    CRTC2_GEN_CNTL__CRTC2_CUR_MODE__MASK                 0x00700000
+#define    CRTC2_GEN_CNTL__CRTC2_CUR_MODE__SHIFT                20
+#define    CRTC2_GEN_CNTL__CRTC2_DISPLAY_DIS                    0x00800000
+#define    CRTC2_GEN_CNTL__CRTC2_EN                             0x02000000
+#define    CRTC2_GEN_CNTL__CRTC2_DISP_REQ_EN_B                  0x04000000
+#define    CRTC2_GEN_CNTL__CRTC2_C_SYNC_EN                      0x08000000
+#define    CRTC2_GEN_CNTL__CRTC2_HSYNC_DIS                      0x10000000
+#define    CRTC2_GEN_CNTL__CRTC2_VSYNC_DIS                      0x20000000
+#define    CRTC2_GEN_CNTL__CRTC2_MODE9_COLOR_ORDER              0x00001000
+#define    CRTC2_GEN_CNTL__CRTC2_FIX_VSYNC_EDGE_POSITION_EN     0x40000000
+#define CRTC2_OFFSET                                        0x00000324
+#define    CRTC2_OFFSET__CRTC2_OFFSET__MASK                     0x07FFFFFF
+#define    CRTC2_OFFSET__CRTC2_OFFSET__SHIFT                    0
+#define    CRTC2_OFFSET__CRTC2_GUI_TRIG_OFFSET                  0x40000000
+#define    CRTC2_OFFSET__CRTC2_OFFSET_LOCK                      0x80000000
+#define    CRTC2_OFFSET__CRTC2_OFFSET_R3__MASK                  0x0FFFFFFF
+#define    CRTC2_OFFSET__CRTC2_OFFSET_R3__SHIFT                 0
+#define CRTC2_OFFSET_CNTL                                   0x00000328
+#define    CRTC2_OFFSET_CNTL__CRTC2_TILE_LINE__MASK             0x0000000F
+#define    CRTC2_OFFSET_CNTL__CRTC2_TILE_LINE__SHIFT            0
+#define    CRTC2_OFFSET_CNTL__CRTC2_TILE_EN                     0x00008000
+#define    CRTC2_OFFSET_CNTL__CRTC2_OFFSET_FLIP_CNTL            0x00010000
+#define    CRTC2_OFFSET_CNTL__CRTC2_GUI_TRIG_OFFSET_LEFT_EN     0x10000000
+#define    CRTC2_OFFSET_CNTL__CRTC2_GUI_TRIG_OFFSET             0x40000000
+#define    CRTC2_OFFSET_CNTL__CRTC2_OFFSET_LOCK                 0x80000000
+#define    CRTC2_OFFSET_CNTL__CRTC2_TILE_LINE_RIGHT__MASK       0x000000F0
+#define    CRTC2_OFFSET_CNTL__CRTC2_TILE_LINE_RIGHT__SHIFT      4
+#define    CRTC2_OFFSET_CNTL__CRTC2_TILE_EN_RIGHT               0x00004000
+#define    CRTC2_OFFSET_CNTL__CRTC2_STEREO_OFFSET_EN            0x00020000
+#define    CRTC2_OFFSET_CNTL__CRTC2_STEREO_SYNC_EN__MASK        0x000C0000
+#define    CRTC2_OFFSET_CNTL__CRTC2_STEREO_SYNC_EN__SHIFT       18
+#define    CRTC2_OFFSET_CNTL__CRTC2_STEREO_SYNC                 0x00200000
+#define    CRTC2_OFFSET_CNTL__CRTC2_GUI_TRIG_OFFSET_RIGHT_EN    0x20000000
+#define    CRTC2_OFFSET_CNTL__CRTC2_X_Y_MODE_EN_RIGHT           0x00000100
+#define    CRTC2_OFFSET_CNTL__CRTC2_X_Y_MODE_EN                 0x00000200
+#define    CRTC2_OFFSET_CNTL__CRTC2_MICRO_TILE_EN_RIGHT         0x00001000
+#define    CRTC2_OFFSET_CNTL__CRTC2_MICRO_TILE_EN               0x00002000
+#define    CRTC2_OFFSET_CNTL__CRTC2_MACRO_TILE_EN_RIGHT         0x00004000
+#define    CRTC2_OFFSET_CNTL__CRTC2_MACRO_TILE_EN               0x00008000
+#define CUR_OFFSET                                          0x00000260
+#define    CUR_OFFSET__CUR_OFFSET__MASK                         0x07FFFFFF
+#define    CUR_OFFSET__CUR_OFFSET__SHIFT                        0
+#define    CUR_OFFSET__CUR_LOCK                                 0x80000000
+#define CUR2_OFFSET                                         0x00000360
+#define    CUR2_OFFSET__CUR2_OFFSET__MASK                       0x07FFFFFF
+#define    CUR2_OFFSET__CUR2_OFFSET__SHIFT                      0
+#define    CUR2_OFFSET__CUR2_LOCK                               0x80000000
+#define HOST_PATH_CNTL                                      0x00000130
+#define    HOST_PATH_CNTL__HDP_APER_CNTL                        0x00800000
+#define    HOST_PATH_CNTL__HP_LIN_RD_CACHE_DIS                  0x01000000
+#define    HOST_PATH_CNTL__HP_RBBM_LOCK_DIS                     0x02000000
+#define    HOST_PATH_CNTL__HDP_SOFT_RESET                       0x04000000
+#define    HOST_PATH_CNTL__HDP_WRITE_COMBINER_TIMEOUT__MASK     0x70000000
+#define    HOST_PATH_CNTL__HDP_WRITE_COMBINER_TIMEOUT__SHIFT    28
+#define    HOST_PATH_CNTL__HP_TEST_RST_CNTL                     0x80000000
+#define    HOST_PATH_CNTL__HDP_WRITE_THROUGH_CACHE_DIS          0x00400000
+#define    HOST_PATH_CNTL__HDP_READ_BUFFER_INVALIDATE           0x08000000
+#define DST_PITCH_OFFSET                                    0x0000142C
+#define    DST_PITCH_OFFSET__DST_OFFSET__MASK                   0x003FFFFF
+#define    DST_PITCH_OFFSET__DST_OFFSET__SHIFT                  0
+#define    DST_PITCH_OFFSET__DST_PITCH__MASK                    0x3FC00000
+#define    DST_PITCH_OFFSET__DST_PITCH__SHIFT                   22
+#define    DST_PITCH_OFFSET__DST_TILE__MASK                     0xC0000000
+#define    DST_PITCH_OFFSET__DST_TILE__SHIFT                    30
+#define    DST_TILE__MACRO                                          0x1
+#define    DST_TILE__MICRO                                          0x2
+#define SRC_PITCH_OFFSET                                    0x00001428
+#define    SRC_PITCH_OFFSET__SRC_OFFSET__MASK                   0x003FFFFF
+#define    SRC_PITCH_OFFSET__SRC_OFFSET__SHIFT                  0
+#define    SRC_PITCH_OFFSET__SRC_PITCH__MASK                    0x3FC00000
+#define    SRC_PITCH_OFFSET__SRC_PITCH__SHIFT                   22
+#define    SRC_PITCH_OFFSET__SRC_TILE                           0x40000000
+#define DEFAULT_SC_BOTTOM_RIGHT                             0x000016E8
+#define    DEFAULT_SC_BOTTOM_RIGHT__DEFAULT_SC_RIGHT__MASK      0x00003FFF
+#define    DEFAULT_SC_BOTTOM_RIGHT__DEFAULT_SC_RIGHT__SHIFT     0
+#define    DEFAULT_SC_BOTTOM_RIGHT__DEFAULT_SC_BOTTOM__MASK     0x3FFF0000
+#define    DEFAULT_SC_BOTTOM_RIGHT__DEFAULT_SC_BOTTOM__SHIFT    16
+#define DEFAULT2_SC_BOTTOM_RIGHT                            0x000016DC
+#define    DEFAULT2_SC_BOTTOM_RIGHT__DEFAULT_SC_RIGHT__MASK     0x00003FFF
+#define    DEFAULT2_SC_BOTTOM_RIGHT__DEFAULT_SC_RIGHT__SHIFT    0
+#define    DEFAULT2_SC_BOTTOM_RIGHT__DEFAULT_SC_BOTTOM__MASK    0x3FFF0000
+#define    DEFAULT2_SC_BOTTOM_RIGHT__DEFAULT_SC_BOTTOM__SHIFT   16
+#define DP_DATATYPE                                         0x000016C4
+#define    DP_DATATYPE__DP_DST_DATATYPE__MASK                   0x0000000F
+#define    DP_DATATYPE__DP_DST_DATATYPE__SHIFT                  0
+#define    DP_DATATYPE__DP_BRUSH_DATATYPE__MASK                 0x00000F00
+#define    DP_DATATYPE__DP_BRUSH_DATATYPE__SHIFT                8
+#define    DP_DATATYPE__DP_SRC_DATATYPE__MASK                   0x00070000
+#define    DP_DATATYPE__DP_SRC_DATATYPE__SHIFT                  16
+#define    DP_DATATYPE__DP_BYTE_PIX_ORDER                       0x40000000
+#define DP_GUI_MASTER_CNTL                                  0x0000146C
+#define    DP_GUI_MASTER_CNTL__GMC_SRC_PITCH_OFFSET_CNTL        0x00000001
+#define    DP_GUI_MASTER_CNTL__GMC_DST_PITCH_OFFSET_CNTL        0x00000002
+#define    DP_GUI_MASTER_CNTL__GMC_SRC_CLIPPING                 0x00000004
+#define    DP_GUI_MASTER_CNTL__GMC_DST_CLIPPING                 0x00000008
+#define    DP_GUI_MASTER_CNTL__GMC_BRUSH_DATATYPE__MASK         0x000000F0
+#define    DP_GUI_MASTER_CNTL__GMC_BRUSH_DATATYPE__SHIFT        4
+#define    GMC_BRUSH_DATATYPE__8X8_MONO_FG_BG                       0x0
+#define    GMC_BRUSH_DATATYPE__8X8_MONO_FG                          0x1
+#define    GMC_BRUSH_DATATYPE__32X1_MONO_LINE_FG_BG                 0x6
+#define    GMC_BRUSH_DATATYPE__32X1_MONO_LINE_FG                    0x7
+#define    GMC_BRUSH_DATATYPE__8X8_COLOR                            0xA
+#define    GMC_BRUSH_DATATYPE__SOLID_COLOR_FG                       0xD
+#define    GMC_BRUSH_DATATYPE__SOLID_COLOR_RESERVED                 0xF
+#define    GMC_BRUSH_DATATYPE__SOLID                                0xD0
+#define    GMC_BRUSH_DATATYPE__MONO8x8                              0x0
+#define    GMC_BRUSH_DATATYPE__COLOR8x8                             0xA0
+#define    DP_GUI_MASTER_CNTL__GMC_DST_DATATYPE__MASK           0x00000F00
+#define    DP_GUI_MASTER_CNTL__GMC_DST_DATATYPE__SHIFT          8
+#define    GMC_DST_DATATYPE__8BPP_CLUT                              0x2
+#define    GMC_DST_DATATYPE__16BPP_1555                             0x3
+#define    GMC_DST_DATATYPE__16BPP_565                              0x4
+#define    GMC_DST_DATATYPE__32BPP_8888                             0x6
+#define    GMC_DST_DATATYPE__CI8                                    0x200
+#define    GMC_DST_DATATYPE__RGB16_1555                             0x300
+#define    GMC_DST_DATATYPE__RGB16_565                              0x400
+#define    GMC_DST_DATATYPE__RGB32                                  0x600
+#define    DP_GUI_MASTER_CNTL__GMC_SRC_DATATYPE__MASK           0x00003000
+#define    DP_GUI_MASTER_CNTL__GMC_SRC_DATATYPE__SHIFT          12
+#define    GMC_SRC_DATATYPE__BUILD(x)                               0x0
+#define    GMC_SRC_DATATYPE__MONO_OPAQUE                            0x0
+#define    GMC_SRC_DATATYPE__MONO_TRANSPARENT                       0x0
+#define    GMC_SRC_DATATYPE__SAME_AS_DST                            0x0
+#define    GMC_SRC_DATATYPE__8BPP_CLUT_XLAT                         0x0
+#define    GMC_SRC_DATATYPE__32BPP_CLUT_XLAT                        0x0
+#define    GMC_SRC_DATATYPE__MONO_FG_BG                             0x0
+#define    GMC_SRC_DATATYPE__MONO_FG                                0x1000
+#define    GMC_SRC_DATATYPE__COLOR                                  0x3000
+#define    GMC_SRC_DATATYPE__DST                                    0x3000
+#define    DP_GUI_MASTER_CNTL__GMC_BYTE_PIX_ORDER               0x00004000
+#define    DP_GUI_MASTER_CNTL__GMC_DEFAULT_SEL                  0x00008000
+#define    DP_GUI_MASTER_CNTL__GMC_ROP3__MASK                   0x00FF0000
+#define    DP_GUI_MASTER_CNTL__GMC_ROP3__SHIFT                  16
+#define    GMC_ROP3__SRCCPY                                         0xCC
+#define    GMC_ROP3__WHITENESS                                      0xFF
+#define    GMC_ROP3__BLACKNESS                                      0x0
+#define    DP_GUI_MASTER_CNTL__GMC_DP_SRC_SOURCE__MASK          0x07000000
+#define    DP_GUI_MASTER_CNTL__GMC_DP_SRC_SOURCE__SHIFT         24
+#define    GMC_DP_SRC_SOURCE__VIDEO_MEM                             0x2
+#define    GMC_DP_SRC_SOURCE__HOSTDATA                              0x3
+#define    GMC_DP_SRC_SOURCE__HOSTDATA_BYTE                         0x4
+#define    DP_GUI_MASTER_CNTL__GMC_SRC_DATATYPE2                0x08000000
+#define    DP_GUI_MASTER_CNTL__GMC_CLR_CMP_FCN_DIS              0x10000000
+#define    DP_GUI_MASTER_CNTL__GMC_WR_MSK_DIS                   0x40000000
+#define DP_BRUSH_FRGD_CLR                                   0x0000147C
+#define    DP_BRUSH_FRGD_CLR__DP_BRUSH_FRGD_CLR__MASK           0xFFFFFFFF
+#define    DP_BRUSH_FRGD_CLR__DP_BRUSH_FRGD_CLR__SHIFT          0
+#define DP_BRUSH_BKGD_CLR                                   0x00001478
+#define    DP_BRUSH_BKGD_CLR__DP_BRUSH_BKGD_CLR__MASK           0xFFFFFFFF
+#define    DP_BRUSH_BKGD_CLR__DP_BRUSH_BKGD_CLR__SHIFT          0
+#define DP_SRC_FRGD_CLR                                     0x000015D8
+#define    DP_SRC_FRGD_CLR__DP_SRC_FRGD_CLR__MASK               0xFFFFFFFF
+#define    DP_SRC_FRGD_CLR__DP_SRC_FRGD_CLR__SHIFT              0
+#define DP_SRC_BKGD_CLR                                     0x000015DC
+#define    DP_SRC_BKGD_CLR__DP_SRC_BKGD_CLR__MASK               0xFFFFFFFF
+#define    DP_SRC_BKGD_CLR__DP_SRC_BKGD_CLR__SHIFT              0
+#define DP_WRITE_MSK                                        0x000016CC
+#define    DP_WRITE_MSK__DP_WRITE_MSK__MASK                     0xFFFFFFFF
+#define    DP_WRITE_MSK__DP_WRITE_MSK__SHIFT                    0
+
+#endif
diff --git a/shared-core/radeon_ms_rom.c b/shared-core/radeon_ms_rom.c
new file mode 100644 (file)
index 0000000..5054a39
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ */
+/*
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#include "radeon_ms.h"
+
+int radeon_ms_rom_get_properties(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+
+       switch (dev_priv->rom.type) {
+       case ROM_COMBIOS:
+               return radeon_ms_combios_get_properties(dev);
+       }
+       return 0;
+}
+
+int radeon_ms_rom_init(struct drm_device *dev)
+{
+       struct drm_radeon_private *dev_priv = dev->dev_private;
+       struct radeon_ms_rom *rom = &dev_priv->rom;
+       void *rom_mapped;
+       char atomstr[5] = {0, 0, 0, 0, 0};
+       uint16_t *offset;
+
+       dev_priv->rom.type = ROM_UNKNOWN;
+       /* copy rom if any */
+       rom_mapped = pci_map_rom_copy(dev->pdev, &rom->rom_size);
+       if (rom->rom_size) {
+               rom->rom_image = drm_alloc(rom->rom_size, DRM_MEM_DRIVER);
+               if (rom->rom_image == NULL) {
+                       return -1;
+               }
+               memcpy(rom->rom_image, rom_mapped, rom->rom_size);
+               DRM_INFO("[radeon_ms] ROM %d bytes copied\n", rom->rom_size);
+       } else {
+               DRM_INFO("[radeon_ms] no ROM\n");
+               return 0;
+       }
+       pci_unmap_rom(dev->pdev, rom_mapped);
+
+       if (rom->rom_image[0] != 0x55 || rom->rom_image[1] != 0xaa) {
+               DRM_INFO("[radeon_ms] no ROM\n");
+               DRM_INFO("[radeon_ms] ROM signature 0x55 0xaa missing\n");
+               return 0;
+       }
+       offset = (uint16_t *)&rom->rom_image[ROM_HEADER];
+       memcpy(atomstr, &rom->rom_image[*offset + 4], 4);
+       if (!strcpy(atomstr, "ATOM") || !strcpy(atomstr, "MOTA")) {
+               DRM_INFO("[radeon_ms] ATOMBIOS ROM detected\n");
+               return 0;
+       } else {
+               struct combios_header **header;
+               
+               header = &rom->rom.combios_header;
+               if ((*offset + sizeof(struct combios_header)) > rom->rom_size) {
+                       DRM_INFO("[radeon_ms] wrong COMBIOS header offset\n");
+                       return -1;
+               }
+               dev_priv->rom.type = ROM_COMBIOS;
+               *header = (struct combios_header *)&rom->rom_image[*offset];
+               DRM_INFO("[radeon_ms] COMBIOS type  : %d\n",
+                        (*header)->ucTypeDefinition);
+               DRM_INFO("[radeon_ms] COMBIOS  OEM ID: %02x %02x\n",
+                        (*header)->ucOemID1, (*header)->ucOemID2);
+       }
+       return 0;
+}
diff --git a/shared-core/radeon_ms_rom.h b/shared-core/radeon_ms_rom.h
new file mode 100644 (file)
index 0000000..36a54cb
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ */
+/*
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#ifndef __RADEON_MS_ROM_H__
+#define __RADEON_MS_ROM_H__
+
+#include "radeon_ms_combios.h"
+
+enum radeon_rom_type {
+       ROM_COMBIOS,
+       ROM_ATOMBIOS,
+       ROM_UNKNOWN
+};
+
+union radeon_ms_rom_type {
+       struct combios_header *combios_header; 
+};
+
+struct radeon_ms_rom {
+       uint8_t                  type;
+       size_t                   rom_size;
+       uint8_t                  *rom_image;
+       union radeon_ms_rom_type rom;
+};
+
+#endif
+
diff --git a/shared-core/radeon_ms_state.c b/shared-core/radeon_ms_state.c
new file mode 100644 (file)
index 0000000..17f8b76
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2007 Jérôme Glisse
+ * 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
+ * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS 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.
+ *
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_ms.h"
+
+void radeon_ms_state_restore(struct drm_device *dev, struct radeon_state *state)
+{
+       radeon_ms_irq_restore(dev, state);
+       radeon_ms_gpu_restore(dev, state);
+       radeon_ms_cp_restore(dev, state);
+       radeon_ms_crtc1_restore(dev, state);
+}
+
+void radeon_ms_state_save(struct drm_device *dev, struct radeon_state *state)
+{
+       radeon_ms_crtc1_save(dev, state);
+       radeon_ms_cp_save(dev, state);
+       radeon_ms_gpu_save(dev, state);
+       radeon_ms_irq_save(dev, state);
+}
index 70651d7..6ff952e 100644 (file)
@@ -3065,7 +3065,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
                 */
        case RADEON_PARAM_SAREA_HANDLE:
                /* The lock is the first dword in the sarea. */
-               value = (long)dev->lock.hw_lock;
+               value = (long)dev->primary->master->lock.hw_lock;
                break;
 #endif
        case RADEON_PARAM_GART_TEX_HANDLE:
index 8985316..48c3b51 100644 (file)
@@ -263,7 +263,7 @@ int main(int argc, char **argv)
 
     for (i = 0; i < 16; i++) if (!minor || i == minor) {
        sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, i);
-       fd = drmOpenMinor(i, 1);
+       fd = drmOpenMinor(i, 1, DRM_NODE_RENDER);
        if (fd >= 0) {
            printf("%s\n", buf);
            if (mask & DRM_BUSID)   getbusid(fd);
diff --git a/tests/mode/Makefile b/tests/mode/Makefile
new file mode 100644 (file)
index 0000000..7a9c3c2
--- /dev/null
@@ -0,0 +1,14 @@
+
+all: app
+
+#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \
+#        -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \
+
+app: modetest.c
+       @gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm modetest.c
+
+clean:
+       @rm -f app
+
+run: app
+       @sudo ./test
diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c
new file mode 100644 (file)
index 0000000..a50b0cc
--- /dev/null
@@ -0,0 +1,380 @@
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "xf86drm.h"
+#include "xf86drmMode.h"
+
+int dpms_prop_id = 0;
+const char* getConnectionText(drmModeConnection conn)
+{
+       switch (conn) {
+       case DRM_MODE_CONNECTED:
+               return "connected";
+       case DRM_MODE_DISCONNECTED:
+               return "disconnected";
+       default:
+               return "unknown";
+       }
+
+}
+
+int printMode(struct drm_mode_modeinfo *mode)
+{
+#if 1
+       printf("Mode: %s\n", mode->name);
+       printf("\tclock       : %i\n", mode->clock);
+       printf("\thdisplay    : %i\n", mode->hdisplay);
+       printf("\thsync_start : %i\n", mode->hsync_start);
+       printf("\thsync_end   : %i\n", mode->hsync_end);
+       printf("\thtotal      : %i\n", mode->htotal);
+       printf("\thskew       : %i\n", mode->hskew);
+       printf("\tvdisplay    : %i\n", mode->vdisplay);
+       printf("\tvsync_start : %i\n", mode->vsync_start);
+       printf("\tvsync_end   : %i\n", mode->vsync_end);
+       printf("\tvtotal      : %i\n", mode->vtotal);
+       printf("\tvscan       : %i\n", mode->vscan);
+       printf("\tvrefresh    : %i\n", mode->vrefresh);
+       printf("\tflags       : %i\n", mode->flags);
+#else
+       printf("Mode: \"%s\" %ix%i %.0f\n", mode->name,
+               mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000.0);
+#endif
+       return 0;
+}
+
+int printOutput(int fd, drmModeResPtr res, drmModeOutputPtr output, uint32_t id)
+{
+       int i = 0, j;
+       struct drm_mode_modeinfo *mode = NULL;
+       drmModePropertyPtr props;
+       unsigned char *name = NULL;
+
+       printf("Output: %d-%d\n", output->output_type, output->output_type_id);
+       printf("\tid           : %i\n", id);
+       printf("\tcrtc id      : %i\n", output->crtc);
+       printf("\tconn         : %s\n", getConnectionText(output->connection));
+       printf("\tsize         : %ix%i (mm)\n", output->mmWidth, output->mmHeight);
+       printf("\tcount_crtcs  : %i\n", output->count_crtcs);
+       printf("\tcrtcs        : %i\n", output->crtcs);
+       printf("\tcount_clones : %i\n", output->count_clones);
+       printf("\tclones       : %i\n", output->clones);
+       printf("\tcount_modes  : %i\n", output->count_modes);
+       printf("\tcount_props  : %i\n", output->count_props);
+
+       for (i = 0; i < output->count_props; i++) {
+               props = drmModeGetProperty(fd, output->props[i]);
+               name = NULL;
+               if (props) {
+                       printf("Property: %s\n", props->name);
+                       printf("\tid:        %i\n", props->prop_id);
+                       printf("\tflags:     %i\n", props->flags);
+                       printf("\tvalues %d: ", props->count_values);
+                       for (j = 0; j < props->count_values; j++)
+                               printf("%lld ", props->values[j]);
+
+                       printf("\n\tenums %d: \n", props->count_enums);
+                       
+                       if (props->flags & DRM_MODE_PROP_BLOB) {
+                               drmModePropertyBlobPtr blob;
+
+                               blob = drmModeGetPropertyBlob(fd, output->prop_values[i]);
+                               if (blob) {
+                                       printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data);
+                                       drmModeFreePropertyBlob(blob);
+                               }
+
+                       } else {
+                               if (!strncmp(props->name, "DPMS", 4))
+                                       dpms_prop_id = props->prop_id;
+
+                               for (j = 0; j < props->count_enums; j++) {
+                                 printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name);
+                                       if (output->prop_values[i] == props->enums[j].value)
+                                               name = props->enums[j].name;
+
+                               }
+
+                               if (props->count_enums && name) {
+                                       printf("\toutput property name %s %s\n", props->name, name);
+                               } else {
+                                       printf("\toutput property id %s %lli\n", props->name, output->prop_values[i]);
+                               }
+                       }
+
+                       drmModeFreeProperty(props);
+               }
+       }
+
+       for (i = 0; i < output->count_modes; i++) {
+               mode = &output->modes[i];
+               if (mode)
+                       printMode(mode);
+               else
+                       printf("\t\tmode: Invalid mode %p\n", &output->modes[i]);
+       }
+
+       return 0;
+}
+
+int printCrtc(int fd, drmModeResPtr res, drmModeCrtcPtr crtc, uint32_t id)
+{
+       printf("Crtc\n");
+       printf("\tid           : %i\n", id);
+       printf("\tx            : %i\n", crtc->x);
+       printf("\ty            : %i\n", crtc->y);
+       printf("\twidth        : %i\n", crtc->width);
+       printf("\theight       : %i\n", crtc->height);
+       printf("\tmode         : %p\n", &crtc->mode);
+       printf("\tnum outputs  : %i\n", crtc->count_outputs);
+       printf("\toutputs      : %i\n", crtc->outputs);
+       printf("\tnum possible : %i\n", crtc->count_possibles);
+       printf("\tpossibles    : %i\n", crtc->possibles);
+
+       return 0;
+}
+
+int printFrameBuffer(int fd, drmModeResPtr res, drmModeFBPtr fb)
+{
+       printf("Framebuffer\n");
+       printf("\thandle    : %i\n", fb->handle);
+       printf("\twidth     : %i\n", fb->width);
+       printf("\theight    : %i\n", fb->height);
+       printf("\tpitch     : %i\n", fb->pitch);;
+       printf("\tbpp       : %i\n", fb->bpp);
+       printf("\tdepth     : %i\n", fb->depth);
+       printf("\tbuffer_id : %i\n", fb->buffer_id);
+
+       return 0;
+}
+
+int printRes(int fd, drmModeResPtr res)
+{
+       int i;
+       drmModeOutputPtr output;
+       drmModeCrtcPtr crtc;
+       drmModeFBPtr fb;
+
+       for (i = 0; i < res->count_outputs; i++) {
+               output = drmModeGetOutput(fd, res->outputs[i]);
+
+               if (!output)
+                       printf("Could not get output %i\n", i);
+               else {
+                       printOutput(fd, res, output, res->outputs[i]);
+                       drmModeFreeOutput(output);
+               }
+       }
+
+       for (i = 0; i < res->count_crtcs; i++) {
+               crtc = drmModeGetCrtc(fd, res->crtcs[i]);
+
+               if (!crtc)
+                       printf("Could not get crtc %i\n", i);
+               else {
+                       printCrtc(fd, res, crtc, res->crtcs[i]);
+                       drmModeFreeCrtc(crtc);
+               }
+       }
+
+       for (i = 0; i < res->count_fbs; i++) {
+               fb = drmModeGetFB(fd, res->fbs[i]);
+
+               if (!fb)
+                       printf("Could not get fb %i\n", res->fbs[i]);
+               else {
+                       printFrameBuffer(fd, res, fb);
+                       drmModeFreeFB(fb);
+               }
+       }
+
+       return 0;
+}
+
+static struct drm_mode_modeinfo mode = {
+       .name = "Test mode",
+       .clock = 25200,
+       .hdisplay = 640,
+       .hsync_start = 656,
+       .hsync_end = 752,
+       .htotal = 800,
+       .hskew = 0,
+       .vdisplay = 480,
+       .vsync_start = 490,
+       .vsync_end = 492,
+       .vtotal = 525,
+       .vscan = 0,
+       .vrefresh = 60000, /* vertical refresh * 1000 */
+       .flags = 10,
+};
+
+int testMode(int fd, drmModeResPtr res)
+{
+       uint32_t output = res->outputs[0];
+       uint32_t newMode = 0;
+       int ret = 0;
+       int error = 0;
+
+       printf("Test: adding mode to output %i\n", output);
+
+       /* printMode(&mode); */
+
+       printf("\tAttaching mode %i to output %i\n", newMode, output);
+
+       ret = drmModeAttachMode(fd, output, &mode);
+
+       if (ret)
+               goto err_mode;
+
+       printf("\tDetaching mode %i from output %i\n", newMode, output);
+       ret = drmModeDetachMode(fd, output, &mode);
+
+       if (ret)
+               goto err_mode;
+       return 0;
+
+err_mode:
+
+       printf("\tFailed\n");
+
+       if (error)
+               printf("\tFailed to delete mode %i\n", newMode);
+       return 1;
+}
+
+/*
+int testFrameBufferGet(int fd, uint32_t fb)
+{
+       drmModeFBPtr frame;
+
+       printf("Test: get framebuffer %i\n", fb);
+
+       frame = drmModeGetFB(fd, fb);
+
+       if (!frame) {
+               printf("\tFailed\n");
+       } else {
+               printFrameBuffer(fd, frame);
+               drmModeFreeFB(frame);
+       }
+
+       return 0;
+}
+*/
+
+int testFrameBufferAdd(int fd, drmModeResPtr res)
+{
+       uint32_t fb = 0;
+       int ret = 0;
+       drmModeFBPtr frame = 0;
+       drmBO bo;
+
+       printf("Test: adding framebuffer\n");
+
+       printf("\tCreating BO\n");
+
+       /* TODO */
+       ret = drmBOCreate(fd, 800 * 600 * 4, 0, 0,
+               DRM_BO_FLAG_READ |
+               DRM_BO_FLAG_WRITE |
+               DRM_BO_FLAG_MEM_TT |
+               DRM_BO_FLAG_MEM_VRAM |
+               DRM_BO_FLAG_NO_EVICT,
+               DRM_BO_HINT_DONT_FENCE, &bo);
+
+       printf("\tgot %i\n", ret);
+       if (ret)
+               goto err;
+
+       printf("\tAdding FB\n");
+       ret = drmModeAddFB(fd, 800, 600, 32, 8, 0, bo->handle, &fb);
+       if (ret)
+               goto err_bo;
+
+       frame = drmModeGetFB(fd, fb);
+
+       if (!frame) {
+               printf("Couldn't retrive created framebuffer\n");
+       } else {
+               printFrameBuffer(fd, res, frame);
+               drmModeFreeFB(frame);
+       }
+
+       printf("\tRemoveing FB\n");
+
+       ret = drmModeRmFB(fd, fb);
+
+       if (ret) {
+               printf("\tFailed this shouldn't happen!\n");
+               goto err_bo;
+       }
+
+       printf("\tRemoveing BO\n");
+
+       ret = drmBOUnreference(fb, &bo);
+
+       return 0;
+       
+err_bo:
+       drmBOUnreference(fd, &bo);
+
+err:
+       printf("\tFailed\n");
+
+       return 1;
+}
+
+int testDPMS(int fd, drmModeResPtr res)
+{
+       int output_id;
+       int i;
+
+       for (i = 0; i < res->count_outputs; i++) {
+               output_id = res->outputs[i];
+               /* turn output off */
+               drmModeOutputSetProperty(fd, output_id, dpms_prop_id, 3);
+               sleep(2);
+               drmModeOutputSetProperty(fd, output_id, dpms_prop_id, 0);
+       }
+       return 1;
+
+}
+
+int main(int argc, char **argv)
+{
+       int fd;
+       drmModeResPtr res;
+
+       printf("Starting test\n");
+
+       fd = drmOpenControl(0);
+
+       if (fd < 0) {
+               printf("Failed to open the card fb (%d)\n",fd);
+               return 1;
+       }
+
+       res = drmModeGetResources(fd);
+       if (res == 0) {
+               printf("Failed to get resources from card\n");
+               drmClose(fd);
+               return 1;
+       }
+
+       printRes(fd, res);
+
+       testMode(fd, res);
+
+       testFrameBufferAdd(fd, res);
+
+       /* try dpms test */
+       testDPMS(fd, res);
+       drmModeFreeResources(res);
+       printf("Ok\n");
+
+       return 0;
+}
diff --git a/tests/mode/test b/tests/mode/test
new file mode 100755 (executable)
index 0000000..f98e370
--- /dev/null
@@ -0,0 +1 @@
+LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app
diff --git a/tests/modedemo/Makefile b/tests/modedemo/Makefile
new file mode 100644 (file)
index 0000000..467fb11
--- /dev/null
@@ -0,0 +1,14 @@
+
+all: app
+
+#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \
+#        -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \
+
+app: demo.c
+       @gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm demo.c
+
+clean:
+       @rm -f app
+
+run: app
+       sudo ./test
diff --git a/tests/modedemo/demo.c b/tests/modedemo/demo.c
new file mode 100644 (file)
index 0000000..83a33aa
--- /dev/null
@@ -0,0 +1,587 @@
+/*
+ * Some defines to define the behavior of the program
+ */
+
+#define CLEAN_FBDEV
+#undef DEMO_CLONE
+
+#define SIZE_X 2048
+#define SIZE_Y 2048
+/* Pitch needs to be power of two */
+#define PITCH 2048
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#ifdef CLEAN_FBDEV
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/fb.h>
+#endif
+
+#include "xf86drm.h"
+#include "xf86drmMode.h"
+
+/* old functions to be replaced */
+drmModeFBPtr createFB(int fd, drmModeResPtr res);
+void testCursor(int fd, uint32_t crtc);
+void prettyColors(int fd, unsigned int handle);
+void prettyCursor(int fd, unsigned int handle, unsigned int color);
+
+#ifdef CLEAN_FBDEV
+struct fb_var_screeninfo var;
+struct fb_fix_screeninfo fix;
+#endif
+
+/* structs for the demo_driver */
+
+struct demo_driver;
+
+struct demo_screen
+{
+       /* drm stuff */
+       drmBO buffer;
+       drmModeFBPtr fb;
+       drmModeCrtcPtr crtc;
+
+       size_t num_outputs;
+       uint32_t outputs_id[8];
+       drmModeOutputPtr outputs[8];
+
+       struct drm_mode_modeinfo *mode;
+
+       /* virtual buffer */
+       uint32_t virt_x;
+       uint32_t virt_y;
+       uint32_t pitch;
+
+       /* parent */
+       struct demo_driver *driver;
+};
+
+#define DEMO_MAX_SCREENS 4
+#define MAX_FIND_OUTPUTS 8
+
+struct demo_driver
+{
+       /* drm stuff */
+       int fd;
+       drmModeResPtr res;
+
+       /* screens */
+       size_t numScreens;
+       struct demo_screen screens[DEMO_MAX_SCREENS];
+};
+
+struct demo_driver* demoCreateDriver(void);
+void demoUpdateRes(struct demo_driver *driver);
+int demoCreateScreens(struct demo_driver *driver);
+int demoCreateScreenCloned(struct demo_driver *driver);
+void demoTakeDownScreen(struct demo_screen *screen);
+int demoFindConnectedOutputs(struct demo_driver *driver, drmModeOutputPtr *out, size_t max_out);
+drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr output);
+void demoPanScreen(struct demo_screen *screen, uint16_t x, uint16_t y);
+/* yet to be implemented */
+void demoMouseActivate(struct demo_screen *screen);
+void demoMouseMove(struct demo_screen *screen, uint16_t x, uint16_t y);
+
+static struct drm_mode_modeinfo mode = {
+       .name = "Test mode",
+       .clock = 25200,
+       .hdisplay = 640,
+       .hsync_start = 656,
+       .hsync_end = 752,
+       .htotal = 800,
+       .hskew = 0,
+       .vdisplay = 480,
+       .vsync_start = 490,
+       .vsync_end = 492,
+       .vtotal = 525,
+       .vscan = 0,
+       .vrefresh = 60000, /* vertical refresh * 1000 */
+       .flags = 10,
+};
+
+int main(int argc, char **argv)
+{
+       struct demo_driver *driver;
+       int num;
+       int i;
+
+#ifdef CLEAN_FBDEV
+       int fbdev_fd;
+
+       fbdev_fd = open("/dev/fb0", O_RDWR);
+
+       memset(&var, 0, sizeof(struct fb_var_screeninfo));
+       memset(&fix, 0, sizeof(struct fb_fix_screeninfo));
+
+       if (ioctl(fbdev_fd, FBIOGET_VSCREENINFO, &var))
+               printf("var  %s\n", strerror(errno));
+       if      (ioctl(fbdev_fd, FBIOGET_FSCREENINFO, &fix))
+               printf("fix %s\n", strerror(errno));
+#endif
+
+       printf("starting demo\n");
+
+       driver = demoCreateDriver();
+
+       if (!driver) {
+               printf("failed to create driver\n");
+               return 1;
+       }
+
+#ifndef DEMO_CLONE
+       num = demoCreateScreens(driver);
+#else
+       num = demoCreateScreenCloned(driver);
+#endif
+
+       if (num < 1) {
+               printf("no screens attached or an error occured\n");
+               return 1;
+       }
+       printf("created %i screens\n", num);
+
+       for (i = 0; i < num; i++) {
+               prettyColors(driver->fd, driver->screens[i].fb->handle);
+       }
+       sleep(1);
+
+       for (i = 0; i < num; i++) {
+               printf("%i: 100 0\n", i);
+               demoPanScreen(&driver->screens[i], 100, 0);
+               sleep(1);
+
+               printf("%i: 0 100\n", i);
+               demoPanScreen(&driver->screens[i], 0, 100);
+               sleep(1);
+
+               printf("%i: 100 100\n", i);
+               demoPanScreen(&driver->screens[i], 100, 100);
+               sleep(1);
+
+               printf("%i: 0 0\n", i);
+               demoPanScreen(&driver->screens[i], 0, 1);
+               sleep(1);
+               testCursor(driver->fd, driver->screens[i].crtc->crtc_id);
+       }
+
+       sleep(2);
+       printf("taking down screens\n");
+       for (i = 0; i < num; i++) {
+               demoTakeDownScreen(&driver->screens[i]);
+       }
+
+#ifdef CLEAN_FBDEV
+       if (ioctl(fbdev_fd, FBIOPUT_VSCREENINFO, &var))
+               printf("var  %s\n", strerror(errno));
+
+       close(fbdev_fd);
+#endif
+
+       printf("ok\n");
+       return 0;
+}
+
+int demoCreateScreens(struct demo_driver *driver)
+{
+       drmModeOutputPtr out[MAX_FIND_OUTPUTS];
+       int num;
+       int num_screens = 0;
+       struct demo_screen *screen;
+       int ret = 0;
+       int i;
+
+       num = demoFindConnectedOutputs(driver, out, MAX_FIND_OUTPUTS);
+       if (num < 0)
+               return 0;
+
+       printf("found %i connected outputs\n", num);
+
+       for (i = 0; i < num; i++) {
+               screen = &driver->screens[i];
+
+               screen->crtc = demoFindFreeCrtc(driver, out[i]);
+               if (!screen->crtc) {
+                       printf("found no free crtc for output\n");
+                       drmModeFreeOutput(out[i]);
+                       continue;
+               }
+
+               screen->fb = createFB(driver->fd, driver->res);
+               if (!screen->fb) {
+                       drmModeFreeOutput(out[i]);
+                       drmModeFreeCrtc(screen->crtc);
+                       screen->crtc = 0;
+                       printf("could not create framebuffer\n");
+                       continue;
+               }
+
+               screen->virt_x = SIZE_X;
+               screen->virt_y = SIZE_Y;
+               screen->pitch = PITCH;
+
+               screen->outputs[0] = out[i];
+               screen->outputs_id[0] = out[i]->output_id;
+               screen->num_outputs = 1;
+
+               screen->mode = &mode;
+               screen->driver = driver;
+
+               ret = drmModeSetCrtc(
+                       driver->fd,
+                       screen->crtc->crtc_id,
+                       screen->fb->buffer_id,
+                       0, 0,
+                       screen->outputs_id, screen->num_outputs,
+                       screen->mode);
+
+               if (ret) {
+                       printf("failed to set mode\n");
+                       demoTakeDownScreen(screen);
+               } else {
+                       num_screens++;
+               }
+
+               demoUpdateRes(driver);
+       }
+
+       return num_screens;
+}
+
+int demoCreateScreenCloned(struct demo_driver *driver)
+{
+       drmModeOutputPtr out[MAX_FIND_OUTPUTS];
+       int num;
+       struct demo_screen *screen;
+       int ret = 0;
+       int i;
+
+       num = demoFindConnectedOutputs(driver, out, MAX_FIND_OUTPUTS);
+       if (num < 0)
+               return 0;
+
+       printf("found %i connected outputs\n", num);
+
+       screen = &driver->screens[0];
+
+       screen->fb = createFB(driver->fd, driver->res);
+       if (!screen->fb) {
+               printf("could not create framebuffer\n");
+               return 0;
+       }
+
+       screen->mode = &mode;
+       screen->driver = driver;
+
+       screen->virt_x = SIZE_X;
+       screen->virt_y = SIZE_Y;
+       screen->pitch = PITCH;
+
+       screen->num_outputs = 0;
+       for (i = 0; i < num; i++) {
+               screen->crtc = demoFindFreeCrtc(driver, out[i]);
+               if (!screen->crtc) {
+                       printf("found no free crtc for output\n");
+                       drmModeFreeOutput(out[i]);
+                       continue;
+               }
+
+               screen->outputs[screen->num_outputs] = out[i];
+               screen->outputs_id[screen->num_outputs] = out[i]->output_id;
+               screen->num_outputs++;
+               printf("%u, %u\n", out[i]->output_id, screen->num_outputs);
+       }
+
+       ret = drmModeSetCrtc(
+                       driver->fd,
+                       screen->crtc->crtc_id,
+                       screen->fb->buffer_id,
+                       0, 0,
+                       screen->outputs_id, screen->num_outputs,
+                       screen->mode);
+
+       if (ret) {
+               printf("failed to set mode\n");
+               demoTakeDownScreen(screen);
+               return 0;
+       }
+
+       demoUpdateRes(driver);
+
+       return 1;
+}
+
+void demoTakeDownScreen(struct demo_screen *screen)
+{
+       int fd = screen->driver->fd;
+       int i;
+       drmBO bo;
+
+#if 0
+       /* This can bust the fbdev arrangement as it basically unhooks
+        * the outputs and the fbdev backend doesn't know how to put things
+        * back on track. Realistically, it's up to the crtc owner to restore
+        * things.....
+        *
+        * So if you are mixing API's make sure the modesetting owner puts
+        * back the original CRTC arrangement so fbdev can continue...
+        *
+        * Ho-hum..
+        */
+       if (screen->crtc)
+               drmModeSetCrtc(fd, screen->crtc->crtc_id, 0, 0, 0, 0, 0, 0);
+#endif
+
+       if (screen->fb)
+               drmModeRmFB(fd, screen->fb->buffer_id);
+
+       /* maybe we should keep a pointer to the bo on the screen */
+       if (screen->fb && !drmBOReference(fd, screen->fb->handle, &bo)) {
+               drmBOUnreference(fd, &bo);
+               drmBOUnreference(fd, &bo);
+       } else {
+               printf("bo error\n");
+       }
+
+       for (i = 0; i < screen->num_outputs; i++) {
+               drmModeFreeOutput(screen->outputs[i]);
+               screen->outputs[i] = NULL;
+       }
+
+       drmModeFreeCrtc(screen->crtc);
+       drmModeFreeFB(screen->fb);
+
+       screen->crtc = NULL;
+       screen->fb = NULL;
+}
+
+drmModeCrtcPtr demoFindFreeCrtc(struct demo_driver *driver, drmModeOutputPtr output)
+{
+       drmModeCrtcPtr crtc;
+       int i, j, used = 0;
+       drmModeResPtr res = driver->res;
+
+       for (i = 0; i < res->count_crtcs; i++) {
+               used = 0;
+               for (j = 0; j < DEMO_MAX_SCREENS; j++) {
+                       crtc = driver->screens[j].crtc;
+
+                       if (crtc && crtc->crtc_id == res->crtcs[i])
+                               used = 1;
+               }
+
+               if (!used) {
+                       crtc = drmModeGetCrtc(driver->fd, res->crtcs[i]);
+                       break;
+               } else {
+                       crtc = 0;
+               }
+       }
+
+       return crtc;
+}
+
+struct demo_driver* demoCreateDriver(void)
+{
+       struct demo_driver* driver = malloc(sizeof(struct demo_driver));
+
+       memset(driver, 0, sizeof(struct demo_driver));
+
+       driver->fd = drmOpen("i915",NULL);
+
+       if (driver->fd < 0) {
+               printf("Failed to open the card fb\n");
+               goto err_driver;
+       }
+
+       demoUpdateRes(driver);
+       if (!driver->res) {
+               printf("could not retrive resources\n");
+               goto err_res;
+       }
+
+       return driver;
+
+err_res:
+       drmClose(driver->fd);
+err_driver:
+       free(driver);
+       return NULL;
+}
+
+void demoUpdateRes(struct demo_driver *driver)
+{
+       if (driver->res)
+               drmModeFreeResources(driver->res);
+
+       driver->res = drmModeGetResources(driver->fd);
+
+       if (!driver->res)
+               printf("failed to get resources from kernel\n");
+}
+
+int demoFindConnectedOutputs(struct demo_driver *driver, drmModeOutputPtr *out, size_t max_out)
+{
+       int count = 0;
+       int i,j;
+       int fd = driver->fd;
+       drmModeResPtr res = driver->res;
+
+       drmModeOutputPtr output;
+
+       for (i = 0; i < res->count_outputs && count < max_out; i++) {
+               output = drmModeGetOutput(fd, res->outputs[i]);
+
+               if (!output)
+                       continue;
+
+               if (output->connection == DRM_MODE_DISCONNECTED) {
+                       drmModeFreeOutput(output);
+                       continue;
+               }
+               
+               for (j = 0; j < output->count_props; j++) {
+                       drmModePropertyPtr prop;
+
+                       prop = drmModeGetProperty(fd, output->props[j]);
+
+                       printf("Property: %s\n",prop->name);
+                       if (prop->count_enums)
+                               printf("%s\n",prop->enums[output->prop_values[j]].name);
+               }
+
+               out[count++] = output;
+       }
+
+       return count;
+}
+
+void demoPanScreen(struct demo_screen *screen, uint16_t x, uint16_t y)
+{
+       drmModeSetCrtc(
+               screen->driver->fd,
+               screen->crtc->crtc_id,
+               screen->fb->buffer_id,
+               x, y,
+               screen->outputs_id, screen->num_outputs,
+               screen->mode);
+}
+
+drmModeFBPtr createFB(int fd, drmModeResPtr res)
+{
+       drmModeFBPtr frame;
+       unsigned int fb = 0;
+       int ret = 0;
+       drmBO bo;
+
+       ret = drmBOCreate(fd, SIZE_X * SIZE_Y * 4, 0, 0,
+               DRM_BO_FLAG_READ |
+               DRM_BO_FLAG_WRITE |
+               DRM_BO_FLAG_MEM_TT |
+               DRM_BO_FLAG_MEM_VRAM |
+               DRM_BO_FLAG_NO_EVICT,
+               DRM_BO_HINT_DONT_FENCE, &bo);
+
+       if (ret) {
+               printf("failed to create framebuffer (ret %d)\n",ret);
+               goto err;
+       }
+
+       ret = drmModeAddFB(fd, SIZE_X, SIZE_Y, 32, 32, PITCH * 4, bo.handle, &fb);
+
+       if (ret)
+               goto err_bo;
+
+       frame = drmModeGetFB(fd, fb);
+
+       if (!frame)
+               goto err_bo;
+
+       return frame;
+
+err_bo:
+       drmBOUnreference(fd, &bo);
+err:
+       return 0;
+}
+
+void draw(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int v, unsigned int *ptr)
+{
+       int i, j;
+
+       for (i = x; i < x + w; i++)
+               for(j = y; j < y + h; j++)
+                       ptr[(i * PITCH) + j] = v;
+
+}
+
+void prettyColors(int fd, unsigned int handle)
+{
+       drmBO bo;
+       unsigned int *ptr;
+       int i;
+
+       drmBOReference(fd, handle, &bo);
+       drmBOMap(fd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr);
+
+       for (i = 0; i < (SIZE_X*SIZE_Y); i++)
+               ptr[i] = 0xFFFFFFFF;
+
+       for (i = 0; i < 8; i++)
+               draw(i * 40, i * 40, 40, 40, 0, ptr);
+
+
+       draw(200, 100, 40, 40, 0xff00ff, ptr);
+       draw(100, 200, 40, 40, 0xff00ff, ptr);
+
+       drmBOUnmap(fd, &bo);
+}
+
+void testCursor(int fd, uint32_t crtc)
+{
+       drmBO bo;
+       int ret;
+       ret = drmBOCreate(fd, 64 * 64 * 4, 0, 0,
+               DRM_BO_FLAG_READ |
+               DRM_BO_FLAG_WRITE |
+               DRM_BO_FLAG_MEM_VRAM |
+               DRM_BO_FLAG_NO_EVICT,
+               DRM_BO_HINT_DONT_FENCE, &bo);
+
+       prettyCursor(fd, bo.handle, 0xFFFF00FF);
+       printf("set cursor\n");
+       drmModeSetCursor(fd, crtc, &bo, 64, 64);
+       printf("move cursor 0, 0\n");
+       drmModeMoveCursor(fd, crtc, 0, 0);
+       sleep(1);
+       prettyCursor(fd, bo.handle, 0xFFFF0000);
+       printf("move cursor 40, 40\n");
+       drmModeMoveCursor(fd, crtc, 40, 40);
+       sleep(1);
+       printf("move cursor 100, 100\n");
+       drmModeMoveCursor(fd, crtc, 100, 100);
+       sleep(1);
+       drmModeSetCursor(fd, crtc, NULL, 0, 0);
+}
+
+void prettyCursor(int fd, unsigned int handle, unsigned int color)
+{
+       drmBO bo;
+       unsigned int *ptr;
+       int i;
+
+       drmBOReference(fd, handle, &bo);
+       drmBOMap(fd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr);
+
+       for (i = 0; i < (64 * 64); i++)
+               ptr[i] = color;
+
+       drmBOUnmap(fd, &bo);
+       drmBOUnreference(fd, &bo);
+}
diff --git a/tests/modedemo/test b/tests/modedemo/test
new file mode 100755 (executable)
index 0000000..f98e370
--- /dev/null
@@ -0,0 +1 @@
+LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app
diff --git a/tests/modefb/Makefile b/tests/modefb/Makefile
new file mode 100644 (file)
index 0000000..467fb11
--- /dev/null
@@ -0,0 +1,14 @@
+
+all: app
+
+#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \
+#        -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \
+
+app: demo.c
+       @gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm demo.c
+
+clean:
+       @rm -f app
+
+run: app
+       sudo ./test
diff --git a/tests/modefb/demo.c b/tests/modefb/demo.c
new file mode 100644 (file)
index 0000000..b6d1f65
--- /dev/null
@@ -0,0 +1,231 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include "linux/fb.h"
+#include <sys/mman.h>
+#include "sys/ioctl.h"
+#include "xf86drm.h"
+#include "xf86drmMode.h"
+
+void pretty(int fd);
+void setMode(struct fb_var_screeninfo *var);
+void pan(int fd, struct fb_var_screeninfo *var, int x, int y);
+void cursor(int fd, int drmfd);
+void prettyColors(int fd);
+void prettyCursor(int fd, unsigned int handle, unsigned int color);
+
+extern void sleep(int);
+
+struct fb_var_screeninfo var;
+struct fb_fix_screeninfo fix;
+
+int main(int argc, char **argv)
+{
+       char name[100];
+       int i,d;
+       int fd;
+       int drmfd = drmOpen("i915", NULL);
+
+       if (drmfd < 0) {
+               printf("drmOpenControl failed\n");
+               return 1;
+       }
+
+       /* try four devices */
+       for (d = 0; d < 4; d++) {
+               snprintf(name, 100, "/dev/fb%d", d);
+               fd = open(name, O_RDWR);
+
+               if (fd == -1) {
+                       printf("open %s : %s\n", name, strerror(errno));
+                       return 1;
+               }
+
+               memset(&var, 0, sizeof(struct fb_var_screeninfo));
+               memset(&fix, 0, sizeof(struct fb_fix_screeninfo));
+
+               if (ioctl(fd, FBIOGET_VSCREENINFO, &var))
+                       printf("var  %s\n", strerror(errno));
+               if      (ioctl(fd, FBIOGET_FSCREENINFO, &fix))
+                       printf("fix %s\n", strerror(errno));
+
+               setMode(&var);
+
+               if (ioctl(fd, FBIOPUT_VSCREENINFO, &var))
+                       printf("var  %s\n", strerror(errno));
+
+               for (i = 0; i < 1; i++) {
+                       prettyColors(fd);
+               }
+               sleep(1);
+
+               printf("pan: 0, 0\n");
+               pan(fd, &var, 0, 0);
+               sleep(2);
+               printf("pan: 100, 0\n");
+               pan(fd, &var, 100, 0);
+               sleep(2);
+               printf("pan: 0, 100\n");
+               pan(fd, &var, 0, 100);
+               sleep(2);
+               printf("pan: 100, 100\n");
+               pan(fd, &var, 100, 100);
+               sleep(2);
+               printf("pan: 0, 0\n");
+               pan(fd, &var, 0, 0);
+               sleep(2);
+
+               printf("cursor (may show up on wrong CRTC - fixme)\n");
+               cursor(fd, drmfd);
+
+               close(fd);
+       }
+       return 0;
+}
+
+void pan(int fd, struct fb_var_screeninfo *var, int x, int y)
+{
+       var->xoffset = x;
+       var->yoffset = y;
+
+       if (ioctl(fd, FBIOPAN_DISPLAY, var))
+               printf("pan error: %s\n", strerror(errno));
+}
+
+void draw(unsigned int x, unsigned int y, unsigned int w, unsigned int h, unsigned int v, unsigned int *ptr)
+{
+       int i, j;
+
+       for (i = x; i < x + w; i++)
+               for(j = y; j < y + h; j++)
+                       ptr[(i * var.xres_virtual) + j] = v;
+}
+
+void prettyColors(int fd)
+{
+       unsigned int *ptr;
+       int i;
+       int size = var.xres * var.yres * var.bits_per_pixel;
+
+       ptr = (unsigned int *)mmap(NULL, size,
+                               PROT_READ|PROT_WRITE, MAP_SHARED, fd,
+                               0);
+       if (ptr < 0) {
+               printf("FAILED MMAP %d\n",errno);
+               exit(1);
+       }
+
+       memset(ptr, 0xFF, size);
+               
+       for (i = 0; i < 8; i++)
+               draw(i * 40, i * 40, 40, 40, 0, ptr);
+
+
+       draw(200, 100, 40, 40, 0xff00ff, ptr);
+       draw(100, 200, 40, 40, 0xff00ff, ptr);
+
+       munmap(ptr, size);
+}
+
+/*
+ * Cursor support removed from the fb kernel interface
+ * using drm instead.
+ */
+void cursor(int fd, int drmfd)
+{
+       drmModeResPtr res = drmModeGetResources(drmfd);
+       uint32_t crtc = res->crtcs[1]; /* select crtc here */
+       drmBO bo;
+       int ret;
+       ret = drmBOCreate(drmfd, 64 * 64 * 4, 0, 0,
+               DRM_BO_FLAG_READ |
+               DRM_BO_FLAG_WRITE |
+               DRM_BO_FLAG_MEM_VRAM |
+               DRM_BO_FLAG_NO_EVICT,
+               DRM_BO_HINT_DONT_FENCE, &bo);
+
+       if (ret) {
+               printf("failed to create buffer: %s\n", strerror(ret));
+               return;
+       }
+
+       prettyCursor(drmfd, bo.handle, 0xFFFF00FF);
+       drmModeSetCursor(drmfd, crtc, &bo, 64, 64);
+       drmModeMoveCursor(drmfd, crtc, 0, 0);
+       sleep(1);
+       prettyCursor(drmfd, bo.handle, 0xFFFF0000);
+       drmModeMoveCursor(drmfd, crtc, 40, 40);
+       sleep(1);
+       drmModeMoveCursor(drmfd, crtc, 100, 100);
+       sleep(1);
+       drmModeSetCursor(drmfd, crtc, NULL, 0, 0);
+       drmBOUnreference(drmfd, &bo);
+}
+
+void prettyCursor(int drmfd, unsigned int handle, unsigned int color)
+{
+       drmBO bo;
+       unsigned int *ptr;
+       int i;
+
+       drmBOReference(drmfd, handle, &bo);
+       drmBOMap(drmfd, &bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, (void**)&ptr);
+
+       for (i = 0; i < (64 * 64); i++)
+               ptr[i] = color;
+
+       drmBOUnmap(drmfd, &bo);
+       drmBOUnreference(drmfd, &bo);
+}
+
+struct drm_mode
+{
+       int clock;
+       int hdisplay;
+       int hsync_start;
+       int hsync_end;
+       int htotal;
+       int hskew;
+       int vdisplay;
+       int vsync_start;
+       int vsync_end;
+       int vtotal;
+       int vscan;
+       int vrefresh;
+       int flags;
+};
+
+struct drm_mode mode =
+{
+       .clock = 25200,
+       .hdisplay = 640,
+       .hsync_start = 656,
+       .hsync_end = 752,
+       .htotal = 800,
+       .hskew = 0,
+       .vdisplay = 480,
+       .vsync_start = 490,
+       .vsync_end = 492,
+       .vtotal = 525,
+       .vscan = 0,
+       .vrefresh = 60000, /* vertical refresh * 1000 */
+       .flags = 10,
+};
+
+void setMode(struct fb_var_screeninfo *var) {
+       var->activate = FB_ACTIVATE_NOW;
+       var->xres = mode.hdisplay;
+       var->right_margin = mode.hsync_start - mode.hdisplay;
+       var->hsync_len = mode.hsync_end - mode.hsync_start;
+       var->left_margin = mode.htotal - mode.hsync_end;
+       var->yres = mode.vdisplay;
+       var->lower_margin = mode.vsync_start - mode.vdisplay;
+       var->vsync_len = mode.vsync_end - mode.vsync_start;
+       var->upper_margin = mode.vtotal - mode.vsync_end;
+       var->pixclock = 10000000 / mode.htotal * 1000 / mode.vtotal * 100;
+       /* avoid overflow */
+       var->pixclock = var->pixclock * 1000 / mode.vrefresh;
+       var->bits_per_pixel = 32;
+}
diff --git a/tests/modefb/test b/tests/modefb/test
new file mode 100755 (executable)
index 0000000..f98e370
--- /dev/null
@@ -0,0 +1 @@
+LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app
diff --git a/tests/modehotplug/Makefile b/tests/modehotplug/Makefile
new file mode 100644 (file)
index 0000000..467fb11
--- /dev/null
@@ -0,0 +1,14 @@
+
+all: app
+
+#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \
+#        -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \
+
+app: demo.c
+       @gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm demo.c
+
+clean:
+       @rm -f app
+
+run: app
+       sudo ./test
diff --git a/tests/modehotplug/demo.c b/tests/modehotplug/demo.c
new file mode 100644 (file)
index 0000000..4ef2e38
--- /dev/null
@@ -0,0 +1,157 @@
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "xf86drm.h"
+#include "xf86drmMode.h"
+
+/* structs for the demo_driver */
+
+#define DEMO_MAX_OUTPUTS 8
+
+struct demo_driver
+{
+       /* drm stuff */
+       int fd;
+       drmModeResPtr res;
+       uint32_t counter;
+
+       drmModeOutputPtr outputs[DEMO_MAX_OUTPUTS];
+};
+
+struct demo_driver* demoCreateDriver(void);
+void demoUpdateRes(struct demo_driver *driver);
+
+void demoPopulateOutputs(struct demo_driver *driver);
+void demoHotplug(struct demo_driver *driver);
+
+const char* demoGetStatus(drmModeOutputPtr out);
+
+int main(int argc, char **argv)
+{
+       struct demo_driver *driver;
+       uint32_t temp;
+       int i;
+
+       printf("starting demo\n");
+
+       driver = demoCreateDriver();
+
+       if (!driver) {
+               printf("failed to create driver\n");
+               return 1;
+       }
+
+       driver->counter = drmModeGetHotplug(driver->fd);
+       demoPopulateOutputs(driver);
+       while (driver->counter != (temp = drmModeGetHotplug(driver->fd))) {
+               demoPopulateOutputs(driver);
+               driver->counter = temp;
+       }
+
+       for (i = 0; i < driver->res->count_outputs && i < DEMO_MAX_OUTPUTS; i++) {
+               printf("Output %u is %s\n",
+                       driver->outputs[i]->output_id,
+                       demoGetStatus(driver->outputs[i]));
+       }
+
+       while(1) {
+               usleep(100000);
+               temp = drmModeGetHotplug(driver->fd);
+               if (temp == driver->counter)
+                       continue;
+
+               demoHotplug(driver);
+               driver->counter = temp;
+       }
+
+       return 0;
+}
+
+const char* demoGetStatus(drmModeOutputPtr output)
+{
+       switch (output->connection) {
+               case DRM_MODE_CONNECTED:
+                       return "connected";
+               case DRM_MODE_DISCONNECTED:
+                       return "disconnected";
+               default:
+                       return "unknown";
+       }
+}
+
+void demoHotplug(struct demo_driver *driver)
+{
+       drmModeResPtr res = driver->res;
+       int i;
+       drmModeOutputPtr temp, current;
+
+       for (i = 0; i < res->count_outputs && i < DEMO_MAX_OUTPUTS; i++) {
+               temp = drmModeGetOutput(driver->fd, res->outputs[i]);
+               current = driver->outputs[i];
+
+               if (temp->connection != current->connection) {
+                       printf("Output %u became %s was %s\n",
+                               temp->output_id,
+                               demoGetStatus(temp),
+                               demoGetStatus(current));
+               }
+
+               drmModeFreeOutput(current);
+               driver->outputs[i] = temp;
+       }
+}
+
+void demoPopulateOutputs(struct demo_driver *driver)
+{
+       drmModeResPtr res = driver->res;
+       int i;
+
+       for (i = 0; i < res->count_outputs && i < DEMO_MAX_OUTPUTS; i++) {
+               drmModeFreeOutput(driver->outputs[i]);
+               driver->outputs[i] = drmModeGetOutput(driver->fd, res->outputs[i]);
+       }
+}
+
+struct demo_driver* demoCreateDriver(void)
+{
+       struct demo_driver* driver = malloc(sizeof(struct demo_driver));
+
+       memset(driver, 0, sizeof(struct demo_driver));
+
+       driver->fd = drmOpen("i915", NULL);
+
+       if (driver->fd < 0) {
+               printf("Failed to open the card fb\n");
+               goto err_driver;
+       }
+
+       demoUpdateRes(driver);
+       if (!driver->res) {
+               printf("could not retrive resources\n");
+               goto err_res;
+       }
+
+       return driver;
+
+err_res:
+       drmClose(driver->fd);
+err_driver:
+       free(driver);
+       return NULL;
+}
+
+void demoUpdateRes(struct demo_driver *driver)
+{
+       if (driver->res)
+               drmModeFreeResources(driver->res);
+
+       driver->res = drmModeGetResources(driver->fd);
+
+       if (!driver->res)
+               printf("failed to get resources from kernel\n");
+}
diff --git a/tests/modehotplug/test b/tests/modehotplug/test
new file mode 100755 (executable)
index 0000000..f98e370
--- /dev/null
@@ -0,0 +1 @@
+LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app