summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdrm/Makefile.am4
-rw-r--r--libdrm/xf86drmMode.c531
-rw-r--r--libdrm/xf86drmMode.h227
-rw-r--r--linux-core/Makefile4
-rw-r--r--linux-core/Makefile.kernel18
-rw-r--r--linux-core/ati_pcigart.c195
-rw-r--r--linux-core/drmP.h23
-rw-r--r--linux-core/drm_bo.c1
-rw-r--r--linux-core/drm_bo_move.c1
-rw-r--r--linux-core/drm_bufs.c7
-rw-r--r--linux-core/drm_compat.h9
-rw-r--r--linux-core/drm_crtc.c2266
-rw-r--r--linux-core/drm_crtc.h621
-rw-r--r--linux-core/drm_drv.c31
-rw-r--r--linux-core/drm_edid.c485
-rw-r--r--linux-core/drm_edid.h176
-rw-r--r--linux-core/drm_fb.c435
-rw-r--r--linux-core/drm_fops.c2
-rw-r--r--linux-core/drm_modes.c560
-rw-r--r--linux-core/drm_objects.h7
-rw-r--r--linux-core/drm_stub.c5
-rw-r--r--linux-core/i915_buffer.c7
-rw-r--r--linux-core/i915_drv.c8
-rw-r--r--linux-core/i915_fence.c4
l---------linux-core/i915_init.c1
-rw-r--r--linux-core/intel_crt.c264
-rw-r--r--linux-core/intel_display.c1235
-rw-r--r--linux-core/intel_drv.h82
-rw-r--r--linux-core/intel_fb.c691
-rw-r--r--linux-core/intel_i2c.c190
-rw-r--r--linux-core/intel_lvds.c508
-rw-r--r--linux-core/intel_modes.c63
-rw-r--r--linux-core/intel_sdvo.c1094
-rw-r--r--linux-core/intel_sdvo_regs.h328
-rw-r--r--linux-core/radeon_buffer.c263
-rw-r--r--linux-core/radeon_drv.c39
-rw-r--r--linux-core/radeon_fence.c125
l---------linux-core/radeon_ms.h1
l---------linux-core/radeon_ms_bo.c1
l---------linux-core/radeon_ms_bus.c1
-rw-r--r--linux-core/radeon_ms_compat.c67
l---------linux-core/radeon_ms_cp.c1
l---------linux-core/radeon_ms_cp_mc.c1
l---------linux-core/radeon_ms_crtc.c1
l---------linux-core/radeon_ms_dac.c1
l---------linux-core/radeon_ms_drm.c1
l---------linux-core/radeon_ms_drm.h1
-rw-r--r--linux-core/radeon_ms_drv.c146
-rw-r--r--linux-core/radeon_ms_drv.h45
l---------linux-core/radeon_ms_exec.c1
l---------linux-core/radeon_ms_family.c1
-rw-r--r--linux-core/radeon_ms_fb.c457
l---------linux-core/radeon_ms_fence.c1
l---------linux-core/radeon_ms_gpu.c1
l---------linux-core/radeon_ms_i2c.c1
l---------linux-core/radeon_ms_irq.c1
l---------linux-core/radeon_ms_output.c1
l---------linux-core/radeon_ms_reg.h1
l---------linux-core/radeon_ms_state.c1
-rw-r--r--shared-core/drm.h141
-rw-r--r--shared-core/drm_pciids.txt4
-rw-r--r--shared-core/i915_dma.c175
-rw-r--r--shared-core/i915_drm.h10
-rw-r--r--shared-core/i915_drv.h153
-rw-r--r--shared-core/i915_init.c329
-rw-r--r--shared-core/i915_irq.c91
-rw-r--r--shared-core/i915_mem.c22
-rw-r--r--shared-core/radeon_cp.c25
-rw-r--r--shared-core/radeon_drm.h9
-rw-r--r--shared-core/radeon_drv.h51
-rw-r--r--shared-core/radeon_irq.c20
-rw-r--r--shared-core/radeon_ms.h607
-rw-r--r--shared-core/radeon_ms_bo.c311
-rw-r--r--shared-core/radeon_ms_bus.c453
-rw-r--r--shared-core/radeon_ms_cp.c345
-rw-r--r--shared-core/radeon_ms_cp_mc.c801
-rw-r--r--shared-core/radeon_ms_crtc.c800
-rw-r--r--shared-core/radeon_ms_dac.c400
-rw-r--r--shared-core/radeon_ms_drm.c298
-rw-r--r--shared-core/radeon_ms_drm.h60
-rw-r--r--shared-core/radeon_ms_exec.c242
-rw-r--r--shared-core/radeon_ms_family.c229
-rw-r--r--shared-core/radeon_ms_fence.c129
-rw-r--r--shared-core/radeon_ms_gpu.c589
-rw-r--r--shared-core/radeon_ms_i2c.c279
-rw-r--r--shared-core/radeon_ms_irq.c160
-rw-r--r--shared-core/radeon_ms_output.c337
-rw-r--r--shared-core/radeon_ms_reg.h1655
-rw-r--r--shared-core/radeon_ms_state.c45
-rw-r--r--tests/mode/Makefile11
-rw-r--r--tests/mode/modetest.c373
-rwxr-xr-xtests/mode/test1
92 files changed, 20129 insertions, 269 deletions
diff --git a/libdrm/Makefile.am b/libdrm/Makefile.am
index e7e07e47..24c32038 100644
--- a/libdrm/Makefile.am
+++ b/libdrm/Makefile.am
@@ -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
diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c
new file mode 100644
index 00000000..726c55ab
--- /dev/null
+++ b/libdrm/xf86drmMode.c
@@ -0,0 +1,531 @@
+/*
+ * \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 "xf86drmMode.h"
+#include "xf86drm.h"
+#include <drm.h>
+#include <string.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;
+}
+
+/**
+ * Generate crtc and output ids.
+ *
+ * Will generate ids starting from 1 up to count if count is greater then 0.
+ */
+static uint32_t* drmAllocGenerate(int count)
+{
+ uint32_t *r;
+ int i;
+
+ if(0 <= count)
+ return 0;
+
+ if (!(r = drmMalloc(count*sizeof(*r))))
+ return 0;
+
+ for (i = 0; i < count; r[i] = ++i);
+
+ return 0;
+}
+
+/*
+ * 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;
+ int i;
+ 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;
+}
+
+int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth,
+ uint8_t bpp, uint32_t pitch, drmBO *bo, 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;
+ int i = 0;
+
+ 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;
+
+err_allocs:
+
+ return 0;
+}
+
+
+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);
+}
+
+
+/*
+ * Output manipulation
+ */
+
+drmModeOutputPtr drmModeGetOutput(int fd, uint32_t output_id)
+{
+ struct drm_mode_get_output out;
+ drmModeOutputPtr r = NULL;
+
+ out.output = output_id;
+ 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));
+ strncpy(r->name, out.name, DRM_OUTPUT_NAME_LEN);
+ r->name[DRM_OUTPUT_NAME_LEN-1] = 0;
+
+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;
+ struct drm_mode_property_blob *blob_tmp;
+ int i;
+ 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;
+}
diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h
new file mode 100644
index 00000000..05b61bc8
--- /dev/null
+++ b/libdrm/xf86drmMode.h
@@ -0,0 +1,227 @@
+/*
+ * \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;
+ unsigned 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 char name[DRM_OUTPUT_NAME_LEN];
+ 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);
+
+
+/*
+ * 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, drmBO *bo,
+ 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);
+
+
+/*
+ * 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);
diff --git a/linux-core/Makefile b/linux-core/Makefile
index 7f6b123e..76ed3e39 100644
--- a/linux-core/Makefile
+++ b/linux-core/Makefile
@@ -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 := m
# Enable module builds for the modules requested/supported.
diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel
index e7c280d0..7ef504ad 100644
--- a/linux-core/Makefile.kernel
+++ b/linux-core/Makefile.kernel
@@ -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 \
+ 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 \
@@ -31,7 +33,13 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \
nv04_graph.o nv10_graph.o nv20_graph.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-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon_fence.o radeon_buffer.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
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 +53,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 +76,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
diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c
index e6187365..5fafbb93 100644
--- a/linux-core/ati_pcigart.c
+++ b/linux-core/ati_pcigart.c
@@ -35,6 +35,45 @@
# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */
+static __inline__ void insert_page_into_table(struct drm_ati_pcigart_info *info, u32 page_base, u32 *pci_gart)
+{
+ switch(info->gart_reg_if) {
+ case DRM_ATI_GART_IGP:
+ *pci_gart = cpu_to_le32((page_base) | 0xc);
+ break;
+ case DRM_ATI_GART_PCIE:
+ *pci_gart = cpu_to_le32((page_base >> 8) | 0xc);
+ break;
+ default:
+ case DRM_ATI_GART_PCI:
+ *pci_gart = cpu_to_le32(page_base);
+ break;
+ }
+}
+
+static __inline__ u32 get_page_base_from_table(struct drm_ati_pcigart_info *info, u32 *pci_gart)
+{
+ u32 retval;
+ switch(info->gart_reg_if) {
+ case DRM_ATI_GART_IGP:
+ retval = *pci_gart;
+ retval &= ~0xc;
+ break;
+ case DRM_ATI_GART_PCIE:
+ retval = *pci_gart;
+ retval &= ~0xc;
+ retval <<= 8;
+ break;
+ default:
+ case DRM_ATI_GART_PCI:
+ retval = *pci_gart;
+ break;
+ }
+ return retval;
+}
+
+
+
static void *drm_ati_alloc_pcigart_table(int order)
{
unsigned long address;
@@ -207,18 +246,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga
page_base = (u32) entry->busaddr[i];
for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
- switch(gart_info->gart_reg_if) {
- case DRM_ATI_GART_IGP:
- *pci_gart = cpu_to_le32((page_base) | 0xc);
- break;
- case DRM_ATI_GART_PCIE:
- *pci_gart = cpu_to_le32((page_base >> 8) | 0xc);
- break;
- default:
- case DRM_ATI_GART_PCI:
- *pci_gart = cpu_to_le32(page_base);
- break;
- }
+ insert_page_into_table(gart_info, page_base, pci_gart);
pci_gart++;
page_base += ATI_PCIGART_PAGE_SIZE;
}
@@ -238,3 +266,146 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga
return ret;
}
EXPORT_SYMBOL(drm_ati_pcigart_init);
+
+static int ati_pcigart_needs_unbind_cache_adjust(struct drm_ttm_backend *backend)
+{
+ return ((backend->flags & DRM_BE_FLAG_BOUND_CACHED) ? 0 : 1);
+}
+
+static int ati_pcigart_populate(struct drm_ttm_backend *backend,
+ unsigned long num_pages,
+ struct page **pages)
+{
+ ati_pcigart_ttm_backend_t *atipci_be =
+ container_of(backend, ati_pcigart_ttm_backend_t, backend);
+
+ DRM_ERROR("%ld\n", num_pages);
+ atipci_be->pages = pages;
+ atipci_be->num_pages = num_pages;
+ atipci_be->populated = 1;
+ return 0;
+}
+
+static int ati_pcigart_bind_ttm(struct drm_ttm_backend *backend,
+ struct drm_bo_mem_reg *bo_mem)
+{
+ ati_pcigart_ttm_backend_t *atipci_be =
+ container_of(backend, ati_pcigart_ttm_backend_t, backend);
+ off_t j;
+ int i;
+ struct drm_ati_pcigart_info *info = atipci_be->gart_info;
+ u32 *pci_gart;
+ u32 page_base;
+ unsigned long offset = bo_mem->mm_node->start;
+ pci_gart = info->addr;
+
+ DRM_ERROR("Offset is %08lX\n", bo_mem->mm_node->start);
+ j = offset;
+ while (j < (offset + atipci_be->num_pages)) {
+ if (get_page_base_from_table(info, pci_gart+j))
+ return -EBUSY;
+ j++;
+ }
+
+ for (i = 0, j = offset; i < atipci_be->num_pages; i++, j++) {
+ struct page *cur_page = atipci_be->pages[i];
+ /* write value */
+ page_base = page_to_phys(cur_page);
+ insert_page_into_table(info, page_base, pci_gart + j);
+ }
+
+#if defined(__i386__) || defined(__x86_64__)
+ wbinvd();
+#else
+ mb();
+#endif
+
+ atipci_be->gart_flush_fn(atipci_be->dev);
+
+ atipci_be->bound = 1;
+ atipci_be->offset = offset;
+ /* need to traverse table and add entries */
+ DRM_DEBUG("\n");
+ return 0;
+}
+
+static int ati_pcigart_unbind_ttm(struct drm_ttm_backend *backend)
+{
+ ati_pcigart_ttm_backend_t *atipci_be =
+ container_of(backend, ati_pcigart_ttm_backend_t, backend);
+ struct drm_ati_pcigart_info *info = atipci_be->gart_info;
+ unsigned long offset = atipci_be->offset;
+ int i;
+ off_t j;
+ u32 *pci_gart = info->addr;
+
+ DRM_DEBUG("\n");
+
+ if (atipci_be->bound != 1)
+ return -EINVAL;
+
+ for (i = 0, j = offset; i < atipci_be->num_pages; i++, j++) {
+ *(pci_gart + j) = 0;
+ }
+ atipci_be->gart_flush_fn(atipci_be->dev);
+ atipci_be->bound = 0;
+ atipci_be->offset = 0;
+ return 0;
+}
+
+static void ati_pcigart_clear_ttm(struct drm_ttm_backend *backend)
+{
+ ati_pcigart_ttm_backend_t *atipci_be =
+ container_of(backend, ati_pcigart_ttm_backend_t, backend);
+
+ DRM_DEBUG("\n");
+ if (atipci_be->pages) {
+ backend->func->unbind(backend);
+ atipci_be->pages = NULL;
+
+ }
+ atipci_be->num_pages = 0;
+}
+
+static void ati_pcigart_destroy_ttm(struct drm_ttm_backend *backend)
+{
+ ati_pcigart_ttm_backend_t *atipci_be;
+ if (backend) {
+ DRM_DEBUG("\n");
+ atipci_be = container_of(backend, ati_pcigart_ttm_backend_t, backend);
+ if (atipci_be) {
+ if (atipci_be->pages) {
+ backend->func->clear(backend);
+ }
+ drm_ctl_free(atipci_be, sizeof(*atipci_be), DRM_MEM_TTM);
+ }
+ }
+}
+
+static struct drm_ttm_backend_func ati_pcigart_ttm_backend =
+{
+ .needs_ub_cache_adjust = ati_pcigart_needs_unbind_cache_adjust,
+ .populate = ati_pcigart_populate,
+ .clear = ati_pcigart_clear_ttm,
+ .bind = ati_pcigart_bind_ttm,
+ .unbind = ati_pcigart_unbind_ttm,
+ .destroy = ati_pcigart_destroy_ttm,
+};
+
+struct drm_ttm_backend *ati_pcigart_init_ttm(struct drm_device *dev, struct drm_ati_pcigart_info *info, void (*gart_flush_fn)(struct drm_device *dev))
+{
+ ati_pcigart_ttm_backend_t *atipci_be;
+
+ atipci_be = drm_ctl_calloc(1, sizeof (*atipci_be), DRM_MEM_TTM);
+ if (!atipci_be)
+ return NULL;
+
+ atipci_be->populated = 0;
+ atipci_be->backend.func = &ati_pcigart_ttm_backend;
+ atipci_be->gart_info = info;
+ atipci_be->gart_flush_fn = gart_flush_fn;
+ atipci_be->dev = dev;
+
+ return &atipci_be->backend;
+}
+EXPORT_SYMBOL(ati_pcigart_init_ttm);
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
index dbf2a924..4a0cabc3 100644
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -175,6 +175,8 @@ struct drm_file;
#include "drm_compat.h"
+#include "drm_crtc.h"
+
/***********************************************************************/
/** \name Macros to make printk easier */
/*@{*/
@@ -432,6 +434,8 @@ struct drm_file {
struct drm_open_hash refd_object_hash[_DRM_NO_REF_TYPES];
struct file *filp;
void *driver_priv;
+
+ struct list_head fbs;
};
/** Wait queue */
@@ -662,6 +666,10 @@ 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);
+
struct drm_fence_driver *fence_driver;
struct drm_bo_driver *bo_driver;
@@ -831,6 +839,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
@@ -842,6 +853,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)
@@ -1159,6 +1181,7 @@ extern int drm_sg_free(struct drm_device *dev, void *data,
/* ATI PCIGART support (ati_pcigart.h) */
extern int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info);
extern int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info);
+extern struct drm_ttm_backend *ati_pcigart_init_ttm(struct drm_device *dev, struct drm_ati_pcigart_info *info, void (*gart_flush_fn)(struct drm_device *dev));
extern drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size,
size_t align, dma_addr_t maxaddr);
diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c
index d308dcfd..7a123dad 100644
--- a/linux-core/drm_bo.c
+++ b/linux-core/drm_bo.c
@@ -2222,6 +2222,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.
diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c
index 971b4af8..97946b3c 100644
--- a/linux-core/drm_bo_move.c
+++ b/linux-core/drm_bo_move.c
@@ -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)
{
diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c
index 75c75c2f..967e9a2d 100644
--- a/linux-core/drm_bufs.c
+++ b/linux-core/drm_bufs.c
@@ -53,8 +53,8 @@ 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))) {
+ ((entry->map->offset == map->offset) ||
+ ((map->type == _DRM_SHM) && (map->flags&_DRM_CONTAINS_LOCK)))) {
return entry;
}
}
@@ -412,6 +412,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->lock.hw_lock = NULL; /* SHM removed */
+ dev->lock.file_priv = NULL;
+ wake_up_interruptible(&dev->lock.lock_queue);
break;
case _DRM_AGP:
case _DRM_SCATTER_GATHER:
diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h
index f8933e0c..3f3abc9a 100644
--- a/linux-core/drm_compat.h
+++ b/linux-core/drm_compat.h
@@ -60,6 +60,13 @@
#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
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c
new file mode 100644
index 00000000..e1b37c0b
--- /dev/null
+++ b/linux-core/drm_crtc.c
@@ -0,0 +1,2266 @@
+/*
+ * 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;
+};
+
+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[] =
+{ { 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" },
+};
+
+
+/**
+ * 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;
+
+ /* Limit to single framebuffer for now */
+ if (dev->mode_config.num_fb > 1) {
+ mutex_unlock(&dev->mode_config.mutex);
+ DRM_ERROR("Attempt to add multiple framebuffers failed\n");
+ return NULL;
+ }
+
+ 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", output->name);
+ /* 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", output->name);
+
+ /* 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",
+ output->name);
+ }
+
+ drm_mode_sort(&output->modes);
+
+ DRM_DEBUG("Probed modes for %s\n", output->name);
+ 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);
+ }
+}
+
+/**
+ * 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;
+ bool ret = false;
+ struct drm_output *output;
+
+ 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;
+
+ /* XXX short-circuit changes to base location only */
+
+ /* 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 (!output->funcs->mode_fixup(output, mode, adjusted_mode)) {
+ goto done;
+ }
+ }
+
+ if (!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", output->name, 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);
+ ret = TRUE;
+ /* TODO */
+// if (scrn->pScreen)
+// drm_crtc_set_screen_sub_pixel_order(dev);
+
+done:
+ if (!ret) {
+ crtc->x = saved_x;
+ crtc->y = saved_y;
+ crtc->mode = saved_mode;
+ }
+
+ 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);
+ }
+}
+
+/**
+ * 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,
+ const char *name)
+{
+ 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);
+ if (name)
+ strncpy(output->name, name, DRM_OUTPUT_LEN);
+ output->name[DRM_OUTPUT_LEN - 1] = 0;
+ 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_output_rename - rename an output
+ * @output: output to rename
+ * @name: new user visible name
+ *
+ * LOCKING:
+ * None.
+ *
+ * Simply stuff a new name into @output's name field, based on @name.
+ *
+ * RETURNS:
+ * True if the name was changed, false otherwise.
+ */
+bool drm_output_rename(struct drm_output *output, const char *name)
+{
+ if (!name)
+ return false;
+
+ strncpy(output->name, name, DRM_OUTPUT_LEN);
+ output->name[DRM_OUTPUT_LEN - 1] = 0;
+
+ DRM_DEBUG("Changed name to %s\n", output->name);
+// drm_output_set_monitor(output);
+// if (drm_output_ignored(output))
+// return FALSE;
+
+ return TRUE;
+}
+EXPORT_SYMBOL(drm_output_rename);
+
+/**
+ * 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;
+
+ 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", 4);
+
+ 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", 10);
+ 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;
+ 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);
+
+}
+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;
+
+ 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;
+
+ des_mode = NULL;
+ list_for_each_entry(des_mode, &output->modes, head) {
+ if (des_mode->type & DRM_MODE_TYPE_PREFERRED)
+ break;
+ }
+
+ /* No preferred mode, let's just select the first available */
+ if (!des_mode || !(des_mode->type & DRM_MODE_TYPE_PREFERRED)) {
+ list_for_each_entry(des_mode, &output->modes, head) {
+ if (des_mode)
+ 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",output->name,output->possible_clones,output_equal->name,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;
+ }
+ }
+}
+
+
+/**
+ * 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) {
+ 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;
+ struct drm_output *output;
+ int count = 0, ro;
+
+ save_crtcs = kzalloc(dev->mode_config.num_crtc * sizeof(struct drm_crtc *), GFP_KERNEL);
+ if (!save_crtcs)
+ return -ENOMEM;
+
+ if (crtc->fb != fb)
+ changed = true;
+
+ if (crtc_info->x != crtc->x || crtc_info->y != crtc->y)
+ changed = 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;
+ }
+ }
+
+ 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);
+ }
+ kfree(save_crtcs);
+ 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);
+ }
+
+ strncpy(out_resp->name, output->name, DRM_OUTPUT_NAME_LEN);
+ out_resp->name[DRM_OUTPUT_NAME_LEN-1] = 0;
+
+ 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;
+ struct drm_output **output_set = NULL, *output;
+ struct drm_framebuffer *fb = NULL;
+ struct drm_display_mode *mode = NULL;
+ int ret = 0;
+ int i;
+ uint32_t __user *set_outputs_ptr;
+
+ 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 (crtc_req->fb_id) {
+ 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);
+ }
+
+ 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;
+ 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:
+ 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;
+ struct drm_crtc *crtc;
+ 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) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* TODO check buffer is sufficently large */
+ /* TODO setup destructor callback */
+
+ fb = drm_framebuffer_create(dev);
+ if (!fb) {
+ 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->offset = bo->offset;
+ fb->bo = bo;
+
+ r->buffer_id = fb->id;
+
+ list_add(&fb->filp_head, &file_priv->fbs);
+
+ /* FIXME: bind the fb to the right crtc */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ crtc->fb = fb;
+ dev->driver->fb_probe(dev, crtc);
+ }
+
+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;
+ uint32_t *id = data;
+ int ret = 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;
+ }
+
+ /* TODO check if we own the buffer */
+ /* TODO release all crtc connected to the framebuffer */
+ /* bind the fb to the crtc for now */
+ /* TODO unhock the destructor from the buffer object */
+
+ if (fb->bo->type != drm_bo_type_kernel)
+ drm_framebuffer_destroy(fb);
+ else
+ dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, 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->head->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_framebuffer_destroy(fb);
+ else
+ dev->driver->fb_remove(dev, drm_crtc_from_fb(dev, 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_output), 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, unsigned char *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
index 00000000..6b6e1dbf
--- /dev/null
+++ b/linux-core/drm_crtc.h
@@ -0,0 +1,621 @@
+/*
+ * 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 long offset;
+ 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];
+ void *virtual_base;
+ 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;
+ unsigned 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);
+ /* 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
+ * @name: name of output (should be one of a few standard names)
+ * @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 */
+ 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 */
+ char name[DRM_OUTPUT_LEN];
+ 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_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;
+};
+
+struct drm_output *drm_output_create(struct drm_device *dev,
+ const struct drm_output_funcs *funcs,
+ const char *name);
+extern void drm_output_destroy(struct drm_output *output);
+extern bool drm_output_rename(struct drm_output *output, const char *name);
+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, unsigned char *edid);
+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_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_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);
+#endif /* __DRM_CRTC_H__ */
+
diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c
index 343d5f32..0b9ce30a 100644
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@ -115,13 +115,21 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
-
DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0),
-
- // DRM_IOCTL_DEF(DRM_IOCTL_BUFOBJ, drm_bo_ioctl, DRM_AUTH),
-
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_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETOUTPUT, drm_mode_getoutput, DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb, DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb, DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, DRM_MASTER|DRM_ROOT_ONLY),
+
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_mode_output_property_set_ioctl, DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_mode_attachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_mode_detachmode_ioctl, DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, DRM_MASTER | DRM_ROOT_ONLY),
DRM_IOCTL_DEF(DRM_IOCTL_MM_INIT, drm_mm_init_ioctl,
DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
@@ -177,8 +185,6 @@ int drm_lastclose(struct drm_device * 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");
@@ -272,11 +278,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 +404,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);
diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c
new file mode 100644
index 00000000..7068cef3
--- /dev/null
+++ b/linux-core/drm_edid.c
@@ -0,0 +1,485 @@
+/*
+ * 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]);
+ 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]);
+ 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 (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);
+ 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",
+ output->name);
+ return NULL;
+ }
+ if (!edid_valid(edid)) {
+ dev_warn(&output->dev->pdev->dev, "%s: EDID invalid.\n",
+ output->name);
+ 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",
+ output->name);
+ 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
index 00000000..0d2eeaa1
--- /dev/null
+++ b/linux-core/drm_edid.h
@@ -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
index 00000000..775fd180
--- /dev/null
+++ b/linux-core/drm_fb.c
@@ -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");
diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c
index 0e1c486c..cc09fc14 100644
--- a/linux-core/drm_fops.c
+++ b/linux-core/drm_fops.c
@@ -263,6 +263,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],
@@ -472,6 +473,7 @@ int drm_release(struct inode *inode, struct file *filp)
mutex_unlock(&dev->ctxlist_mutex);
mutex_lock(&dev->struct_mutex);
+ drm_fb_release(filp);
drm_object_release(filp);
if (file_priv->remove_auth_on_close == 1) {
struct drm_file *temp;
diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c
new file mode 100644
index 00000000..3763ca69
--- /dev/null
+++ b/linux-core/drm_modes.c
@@ -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);
+ }
+ }
+}
diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h
index 1dc61fde..394a2721 100644
--- a/linux-core/drm_objects.h
+++ b/linux-core/drm_objects.h
@@ -157,7 +157,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;
@@ -486,12 +485,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);
@@ -629,6 +628,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.
diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c
index 00a24521..cc759d5c 100644
--- a/linux-core/drm_stub.c
+++ b/linux-core/drm_stub.c
@@ -86,9 +86,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);
@@ -135,7 +135,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
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");
diff --git a/linux-core/i915_buffer.c b/linux-core/i915_buffer.c
index b000a725..c455a515 100644
--- a/linux-core/i915_buffer.c
+++ b/linux-core/i915_buffer.c
@@ -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;
@@ -130,7 +133,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)
diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c
index d2bcf4b5..fb4149c4 100644
--- a/linux-core/i915_drv.c
+++ b/linux-core/i915_drv.c
@@ -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"
@@ -52,8 +53,8 @@ static 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_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_VRAM, DRM_BO_MEM_LOCAL};
static struct drm_bo_driver i915_bo_driver = {
.mem_type_prio = i915_mem_prios,
@@ -540,7 +541,6 @@ static struct drm_driver driver = {
DRIVER_IRQ_VBL2,
.load = i915_driver_load,
.unload = i915_driver_unload,
- .firstopen = i915_driver_firstopen,
.lastclose = i915_driver_lastclose,
.preclose = i915_driver_preclose,
.suspend = i915_suspend,
@@ -555,6 +555,8 @@ 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,
.ioctls = i915_ioctls,
.fops = {
.owner = THIS_MODULE,
diff --git a/linux-core/i915_fence.c b/linux-core/i915_fence.c
index e3c76df6..21d032b0 100644
--- a/linux-core/i915_fence.c
+++ b/linux-core/i915_fence.c
@@ -40,7 +40,7 @@
static void i915_perform_flush(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_fence_manager *fm = &dev->fm;
struct drm_fence_class_manager *fc = &fm->fence_class[0];
struct drm_fence_driver *driver = dev->driver->fence_driver;
@@ -124,7 +124,7 @@ 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 (!dev_priv)
return -EINVAL;
diff --git a/linux-core/i915_init.c b/linux-core/i915_init.c
new file mode 120000
index 00000000..473ddf7b
--- /dev/null
+++ b/linux-core/i915_init.c
@@ -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
index 00000000..722a62c8
--- /dev/null
+++ b/linux-core/intel_crt.c
@@ -0,0 +1,264 @@
+/*
+ * 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;
+ 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;
+}
+
+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;
+ int i;
+
+ 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, "VGA");
+
+ 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
index 00000000..a81cfe69
--- /dev/null
+++ b/linux-core/intel_display.c
@@ -0,0 +1,1235 @@
+/*
+ * 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 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);
+
+ Start = crtc->fb->offset;
+ Offset = y * crtc->fb->pitch + x;
+
+ 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_priv->sarea_priv)
+ return;
+
+ switch (pipe) {
+ case 0:
+ dev_priv->sarea_priv->planeA_x = x;
+ dev_priv->sarea_priv->planeA_y = y;
+ break;
+ case 1:
+ dev_priv->sarea_priv->planeB_x = x;
+ dev_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_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_priv->sarea_priv)
+ return;
+
+ enabled = crtc->enabled && mode != DPMSModeOff;
+
+ switch (pipe) {
+ case 0:
+ dev_priv->sarea_priv->planeA_w = enabled ? crtc->mode.hdisplay : 0;
+ dev_priv->sarea_priv->planeA_h = enabled ? crtc->mode.vdisplay : 0;
+ break;
+ case 1:
+ dev_priv->sarea_priv->planeB_w = enabled ? crtc->mode.hdisplay : 0;
+ dev_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 dspstride_reg = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
+ 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;
+
+ 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 32:
+ dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
+ break;
+ default:
+ DRM_ERROR("Unknown color depth\n");
+ return;
+ }
+
+
+ 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));
+ I915_WRITE(dspstride_reg, crtc->fb->pitch);
+ /* 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]);
+ }
+}
+
+/** 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,
+ .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;
+ }
+
+ 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
index 00000000..7de4b924
--- /dev/null
+++ b/linux-core/intel_drv.h
@@ -0,0 +1,82 @@
+/*
+ * 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_tmp;
+ void *dev_priv;
+};
+
+struct intel_crtc {
+ int pipe;
+ 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 int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc);
+extern int intelfb_remove(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
index 00000000..32c7dc31
--- /dev/null
+++ b/linux-core/intel_fb.c
@@ -0,0 +1,691 @@
+/*
+ * 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;
+};
+
+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->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 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->crtc->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;
+}
+
+bool i915_drmfb_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2, unsigned int pixclock)
+{
+
+ 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)
+ {
+ if (mode1->clock == mode2->clock)
+ return true;
+
+ if (KHZ2PICOS(mode2->clock) == pixclock)
+ return true;
+ return false;
+ }
+
+ return false;
+}
+
+/* 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->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:
+ 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);
+
+ 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 (i915_drmfb_mode_equal(drm_mode, search_mode, var->pixclock)) {
+ 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;
+}
+
+#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 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,
+};
+
+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;
+
+ 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;
+ 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_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->offset = fbo->offset;
+ 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;
+
+ 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 = 8;
+ info->fix.ypanstep = 1;
+ info->fix.ywrapstep = 0;
+ info->fix.accel = FB_ACCEL_I830;
+ 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; /* 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);
+ 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(intelfb_remove);
+MODULE_LICENSE("GPL");
diff --git a/linux-core/intel_i2c.c b/linux-core/intel_i2c.c
new file mode 100644
index 00000000..efcbf656
--- /dev/null
+++ b/linux-core/intel_i2c.c
@@ -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
index 00000000..94232b94
--- /dev/null
+++ b/linux-core/intel_lvds.c
@@ -0,0 +1,508 @@
+/*
+ * 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, "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
index 00000000..f8bf496c
--- /dev/null
+++ b/linux-core/intel_modes.c
@@ -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
index 00000000..0da57faa
--- /dev/null
+++ b/linux-core/intel_sdvo.c
@@ -0,0 +1,1094 @@
+/*
+ * 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;
+};
+
+/**
+ * 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).
+ */
+static 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);
+ else
+ bval = I915_READ(SDVOB);
+ /*
+ * 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)
+{
+
+}
+
+
+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;
+ char name[DRM_OUTPUT_LEN];
+ char *name_prefix;
+ char *name_suffix;
+
+
+ output = drm_output_create(dev, &intel_sdvo_output_funcs, NULL);
+ 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) {
+ name_suffix = "-1";
+ sdvo_priv->i2c_bus->slave_addr = 0x38;
+ } else {
+ name_suffix = "-2";
+ sdvo_priv->i2c_bus->slave_addr = 0x39;
+ }
+
+ sdvo_priv->output_device = output_device;
+ 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;
+ name_prefix="RGB";
+ connector_type = ConnectorVGA;
+ }
+ else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1)
+ {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1;
+ output->subpixel_order = SubPixelHorizontalRGB;
+ name_prefix="RGB";
+ connector_type = ConnectorVGA;
+ }
+ else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
+ {
+ sdvo_priv->active_outputs = SDVO_OUTPUT_TMDS0;
+ output->subpixel_order = SubPixelHorizontalRGB;
+ name_prefix="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;
+ name_prefix="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;
+ }
+ strcpy (name, name_prefix);
+ strcat (name, name_suffix);
+ if (!drm_output_rename(output, name))
+ {
+ drm_output_destroy(output);
+ return;
+ }
+
+
+ /* 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
index 00000000..a9d16711
--- /dev/null
+++ b/linux-core/intel_sdvo_regs.h
@@ -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/radeon_buffer.c b/linux-core/radeon_buffer.c
new file mode 100644
index 00000000..8e2b20b1
--- /dev/null
+++ b/linux-core/radeon_buffer.c
@@ -0,0 +1,263 @@
+/**************************************************************************
+ *
+ * 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>
+ */
+
+#include "drmP.h"
+#include "radeon_drm.h"
+#include "radeon_drv.h"
+
+struct drm_ttm_backend *radeon_create_ttm_backend_entry(struct drm_device * dev)
+{
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+
+ if(dev_priv->flags & RADEON_IS_AGP)
+ return drm_agp_init_ttm(dev);
+ else
+ return ati_pcigart_init_ttm(dev, &dev_priv->gart_info, radeon_gart_flush);
+}
+
+int radeon_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;
+}
+
+int radeon_invalidate_caches(struct drm_device * dev, uint64_t flags)
+{
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ RING_LOCALS;
+
+ BEGIN_RING(4);
+ RADEON_FLUSH_CACHE();
+ RADEON_FLUSH_ZCACHE();
+ ADVANCE_RING();
+ return 0;
+}
+
+uint32_t radeon_evict_mask(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_init_mem_type(struct drm_device * dev, uint32_t type,
+ struct drm_mem_type_manager * man)
+{
+ drm_radeon_private_t *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 = drm_get_resource_start(dev, 0);
+ man->io_size = drm_get_resource_len(dev, 0);
+ break;
+ case DRM_BO_MEM_TT:
+ if (dev_priv->flags & RADEON_IS_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;
+ } else {
+ man->io_offset = dev_priv->gart_vm_start;
+ man->io_size = dev_priv->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;
+ default:
+ DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void radeon_emit_copy_blit(struct drm_device * dev,
+ uint32_t src_offset,
+ uint32_t dst_offset,
+ uint32_t pages, int direction)
+{
+ uint32_t cur_pages;
+ uint32_t stride = PAGE_SIZE;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ uint32_t format, height;
+ RING_LOCALS;
+
+ if (!dev_priv)
+ return;
+
+ /* 32-bit copy format */
+ format = RADEON_COLOR_FORMAT_ARGB8888;
+
+ /* radeon limited to 16k stride */
+ stride &= 0x3fff;
+ while(pages > 0) {
+ cur_pages = pages;
+ if (cur_pages > 2048)
+ cur_pages = 2048;
+ pages -= cur_pages;
+
+ /* needs verification */
+ BEGIN_RING(7);
+ OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
+ OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
+ RADEON_GMC_DST_PITCH_OFFSET_CNTL |
+ RADEON_GMC_BRUSH_NONE |
+ (format << 8) |
+ RADEON_GMC_SRC_DATATYPE_COLOR |
+ RADEON_ROP3_S |
+ RADEON_DP_SRC_SOURCE_MEMORY |
+ RADEON_GMC_CLR_CMP_CNTL_DIS | RADEON_GMC_WR_MSK_DIS);
+ if (direction) {
+ OUT_RING((stride << 22) | (src_offset >> 10));
+ OUT_RING((stride << 22) | (dst_offset >> 10));
+ } else {
+ OUT_RING((stride << 22) | (dst_offset >> 10));
+ OUT_RING((stride << 22) | (src_offset >> 10));
+ }
+ OUT_RING(0);
+ OUT_RING(pages); /* x - y */
+ OUT_RING((stride << 16) | cur_pages);
+ ADVANCE_RING();
+ }
+
+ BEGIN_RING(2);
+ RADEON_WAIT_UNTIL_2D_IDLE();
+ ADVANCE_RING();
+
+ return;
+}
+
+static int radeon_move_blit(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;
+ int dir = 0;
+
+ if ((old_mem->mem_type == new_mem->mem_type) &&
+ (new_mem->mm_node->start <
+ old_mem->mm_node->start + old_mem->mm_node->size)) {
+ dir = 1;
+ }
+
+ radeon_emit_copy_blit(bo->dev,
+ old_mem->mm_node->start << PAGE_SHIFT,
+ new_mem->mm_node->start << PAGE_SHIFT,
+ new_mem->num_pages, dir);
+
+
+ return 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);
+}
+
+static int radeon_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.mask = 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_bind_ttm(bo->ttm, &tmp_mem);
+ if (ret)
+ goto out_cleanup;
+
+ ret = radeon_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_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;
+
+ DRM_DEBUG("\n");
+ 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_move_flip(bo, evict, no_wait, new_mem))
+ return drm_bo_move_memcpy(bo, evict, no_wait, new_mem);
+ } else {
+ if (radeon_move_blit(bo, evict, no_wait, new_mem))
+ return drm_bo_move_memcpy(bo, evict, no_wait, new_mem);
+ }
+ return 0;
+}
+
diff --git a/linux-core/radeon_drv.c b/linux-core/radeon_drv.c
index d847f3cd..2e491304 100644
--- a/linux-core/radeon_drv.c
+++ b/linux-core/radeon_drv.c
@@ -56,6 +56,38 @@ static struct pci_device_id pciidlist[] = {
radeon_PCI_IDS
};
+
+#ifdef RADEON_HAVE_FENCE
+static struct drm_fence_driver radeon_fence_driver = {
+ .num_classes = 1,
+ .wrap_diff = (1 << 30),
+ .flush_diff = (1 << 29),
+ .sequence_mask = 0xffffffffU,
+ .lazy_capable = 1,
+ .emit = radeon_fence_emit_sequence,
+ .poke_flush = radeon_poke_flush,
+ .has_irq = radeon_fence_has_irq,
+};
+#endif
+#ifdef RADEON_HAVE_BUFFER
+
+static uint32_t radeon_mem_prios[] = {DRM_BO_MEM_VRAM, DRM_BO_MEM_TT, DRM_BO_MEM_LOCAL};
+static uint32_t radeon_busy_prios[] = {DRM_BO_MEM_TT, DRM_BO_MEM_VRAM, DRM_BO_MEM_LOCAL};
+
+static struct drm_bo_driver radeon_bo_driver = {
+ .mem_type_prio = radeon_mem_prios,
+ .mem_busy_prio = radeon_busy_prios,
+ .num_mem_type_prio = sizeof(radeon_mem_prios)/sizeof(uint32_t),
+ .num_mem_busy_prio = sizeof(radeon_busy_prios)/sizeof(uint32_t),
+ .create_ttm_backend_entry = radeon_create_ttm_backend_entry,
+ .fence_type = radeon_fence_types,
+ .invalidate_caches = radeon_invalidate_caches,
+ .init_mem_type = radeon_init_mem_type,
+ .evict_mask = radeon_evict_mask,
+ .move = radeon_move,
+};
+#endif
+
static int probe(struct pci_dev *pdev, const struct pci_device_id *ent);
static struct drm_driver driver = {
.driver_features =
@@ -101,6 +133,13 @@ static struct drm_driver driver = {
.remove = __devexit_p(drm_cleanup_pci),
},
+#ifdef RADEON_HAVE_FENCE
+ .fence_driver = &radeon_fence_driver,
+#endif
+#ifdef RADEON_HAVE_BUFFER
+ .bo_driver = &radeon_bo_driver,
+#endif
+
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
diff --git a/linux-core/radeon_fence.c b/linux-core/radeon_fence.c
new file mode 100644
index 00000000..682f0bee
--- /dev/null
+++ b/linux-core/radeon_fence.c
@@ -0,0 +1,125 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
+ * 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: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_drm.h"
+#include "radeon_drv.h"
+
+/*
+ * Implements an intel sync flush operation.
+ */
+
+static void radeon_perform_flush(struct drm_device * dev)
+{
+ drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
+ struct drm_fence_manager *fm = &dev->fm;
+ struct drm_fence_class_manager *fc = &dev->fm.fence_class[0];
+ struct drm_fence_driver *driver = dev->driver->fence_driver;
+ uint32_t pending_flush_types = 0;
+ uint32_t sequence;
+
+ if (!dev_priv)
+ return;
+
+ pending_flush_types = fc->pending_flush |
+ ((fc->pending_exe_flush) ? DRM_FENCE_TYPE_EXE : 0);
+
+ if (pending_flush_types) {
+ sequence = READ_BREADCRUMB(dev_priv);
+
+ drm_fence_handler(dev, 0, sequence, pending_flush_types, 0);
+ }
+
+ return;
+}
+
+void radeon_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_perform_flush(dev);
+ write_unlock_irqrestore(&fm->lock, flags);
+}
+
+int radeon_fence_emit_sequence(struct drm_device *dev, uint32_t class,
+ uint32_t flags, uint32_t *sequence,
+ uint32_t *native_type)
+{
+ drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
+ RING_LOCALS;
+
+ if (!dev_priv)
+ return -EINVAL;
+
+ *native_type = DRM_FENCE_TYPE_EXE;
+ if (flags & DRM_RADEON_FENCE_FLAG_FLUSHED) {
+ *native_type |= DRM_RADEON_FENCE_TYPE_RW;
+
+ BEGIN_RING(4);
+
+ RADEON_FLUSH_CACHE();
+ RADEON_FLUSH_ZCACHE();
+ ADVANCE_RING();
+ }
+
+ radeon_emit_irq(dev);
+ *sequence = (uint32_t) dev_priv->counter;
+
+
+ return 0;
+}
+
+void radeon_fence_handler(struct drm_device * dev)
+{
+ struct drm_fence_manager *fm = &dev->fm;
+
+ write_lock(&fm->lock);
+ radeon_perform_flush(dev);
+ write_unlock(&fm->lock);
+}
+
+int radeon_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;
+}
diff --git a/linux-core/radeon_ms.h b/linux-core/radeon_ms.h
new file mode 120000
index 00000000..da340c5d
--- /dev/null
+++ b/linux-core/radeon_ms.h
@@ -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
index 00000000..d05df59f
--- /dev/null
+++ b/linux-core/radeon_ms_bo.c
@@ -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
index 00000000..50f649d0
--- /dev/null
+++ b/linux-core/radeon_ms_bus.c
@@ -0,0 +1 @@
+../shared-core/radeon_ms_bus.c \ 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
index 00000000..6efdc786
--- /dev/null
+++ b/linux-core/radeon_ms_compat.c
@@ -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
index 00000000..6aee3e6e
--- /dev/null
+++ b/linux-core/radeon_ms_cp.c
@@ -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
index 00000000..0ae1a647
--- /dev/null
+++ b/linux-core/radeon_ms_cp_mc.c
@@ -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
index 00000000..31f11447
--- /dev/null
+++ b/linux-core/radeon_ms_crtc.c
@@ -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
index 00000000..cb523cfb
--- /dev/null
+++ b/linux-core/radeon_ms_dac.c
@@ -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
index 00000000..8bbf19a5
--- /dev/null
+++ b/linux-core/radeon_ms_drm.c
@@ -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
index 00000000..5d9d7319
--- /dev/null
+++ b/linux-core/radeon_ms_drm.h
@@ -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
index 00000000..4b52a7d7
--- /dev/null
+++ b/linux-core/radeon_ms_drv.c
@@ -0,0 +1,146 @@
+/*
+ * 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,
+ .vblank_wait = NULL,
+ .vblank_wait2 = 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 |
+ DRIVER_IRQ_VBL | DRIVER_IRQ_VBL2,
+ .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
index 00000000..529f9c42
--- /dev/null
+++ b/linux-core/radeon_ms_drv.h
@@ -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
index 00000000..cb397fbf
--- /dev/null
+++ b/linux-core/radeon_ms_exec.c
@@ -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
index 00000000..1f12e092
--- /dev/null
+++ b/linux-core/radeon_ms_family.c
@@ -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
index 00000000..fc9e99ec
--- /dev/null
+++ b/linux-core/radeon_ms_fb.c
@@ -0,0 +1,457 @@
+/*
+ * 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;
+ }
+
+ fb->offset = fb->bo->offset;
+ 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->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
index 00000000..383cc070
--- /dev/null
+++ b/linux-core/radeon_ms_fence.c
@@ -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
index 00000000..fa5e05bf
--- /dev/null
+++ b/linux-core/radeon_ms_gpu.c
@@ -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
index 00000000..1863e6d6
--- /dev/null
+++ b/linux-core/radeon_ms_i2c.c
@@ -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
index 00000000..c4e60ba6
--- /dev/null
+++ b/linux-core/radeon_ms_irq.c
@@ -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
index 00000000..6a38b671
--- /dev/null
+++ b/linux-core/radeon_ms_output.c
@@ -0,0 +1 @@
+../shared-core/radeon_ms_output.c \ 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
index 00000000..24b01b42
--- /dev/null
+++ b/linux-core/radeon_ms_reg.h
@@ -0,0 +1 @@
+../shared-core/radeon_ms_reg.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
index 00000000..2d2e2ef7
--- /dev/null
+++ b/linux-core/radeon_ms_state.c
@@ -0,0 +1 @@
+../shared-core/radeon_ms_state.c \ No newline at end of file
diff --git a/shared-core/drm.h b/shared-core/drm.h
index 70a25b24..9a8dc1d2 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -893,6 +893,133 @@ struct drm_mm_init_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;
+};
+
+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 char name[DRM_OUTPUT_NAME_LEN];
+
+ 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;
+};
+
/**
* \name Ioctls Definitions
*/
@@ -985,6 +1112,20 @@ struct drm_mm_init_arg {
#define DRM_IOCTL_BO_VERSION DRM_IOR(0xd6, struct drm_bo_version_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)
/*@}*/
/**
diff --git a/shared-core/drm_pciids.txt b/shared-core/drm_pciids.txt
index 05d32f2e..a76413d4 100644
--- a/shared-core/drm_pciids.txt
+++ b/shared-core/drm_pciids.txt
@@ -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"
diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c
index 80416726..23e8b491 100644
--- a/shared-core/i915_dma.c
+++ b/shared-core/i915_dma.c
@@ -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,8 @@ 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);
ring->head = I915_READ(LP_RING + RING_HEAD) & HEAD_ADDR;
ring->tail = I915_READ(LP_RING + RING_TAIL) & TAIL_ADDR;
@@ -73,9 +73,8 @@ 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;
/* 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,32 +82,12 @@ 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->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);
- }
-
return 0;
}
static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = dev->dev_private;
dev_priv->sarea = drm_getsarea(dev);
if (!dev_priv->sarea) {
@@ -197,7 +176,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
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");
@@ -236,7 +215,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) {
@@ -336,7 +315,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;
@@ -377,7 +356,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;
@@ -418,7 +397,7 @@ 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;
RING_LOCALS;
if (++dev_priv->counter > BREADCRUMB_MASK) {
@@ -439,7 +418,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;
@@ -459,10 +438,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;
@@ -499,7 +478,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;
@@ -552,7 +531,7 @@ 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;
u32 num_pages, current_page, next_page, dspbase;
int shift = 2 * plane, x, y;
RING_LOCALS;
@@ -604,7 +583,7 @@ static void i915_do_dispatch_flip(struct drm_device * dev, int plane, int sync)
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;
int i;
DRM_DEBUG("planes=0x%x pfCurrentPage=%d\n",
@@ -625,7 +604,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__);
@@ -643,7 +622,7 @@ 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;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv;
drm_i915_batchbuffer_t *batch = data;
@@ -673,10 +652,10 @@ 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 *)
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+ struct drm_i915_sarea *sarea_priv = (struct drm_i915_sarea *)
dev_priv->sarea_priv;
- drm_i915_cmdbuffer_t *cmdbuf = data;
+ struct drm_i915_cmdbuffer *cmdbuf = data;
int ret;
DRM_DEBUG("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
@@ -1040,11 +1019,11 @@ out_err:
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;
drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
dev_priv->sarea_priv;
struct drm_i915_execbuffer *exec_buf = data;
- struct _drm_i915_batchbuffer *batch = &exec_buf->batch;
+ struct drm_i915_batchbuffer *batch = &exec_buf->batch;
struct drm_fence_arg *fence_arg = &exec_buf->fence_arg;
int num_buffers;
int ret;
@@ -1143,14 +1122,14 @@ out_free:
}
#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_private *dev_priv = dev->dev_private;
+ int i, planes, num_pages;
DRM_DEBUG("\n");
-
- for (i = 0, planes = 0; i < 2; i++)
+ num_pages = dev_priv->sarea_priv->third_handle ? 3 : 2;
+ 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 &
@@ -1158,6 +1137,7 @@ static int i915_do_cleanup_pageflip(struct drm_device * dev)
planes |= 1 << i;
}
+ }
if (planes)
i915_dispatch_flip(dev, planes, 0);
@@ -1167,7 +1147,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");
@@ -1189,8 +1169,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) {
@@ -1224,7 +1204,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) {
@@ -1265,8 +1245,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;
@@ -1311,7 +1291,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) {
@@ -1339,85 +1319,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));
-
- 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),
@@ -1460,10 +1368,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;
-}
diff --git a/shared-core/i915_drm.h b/shared-core/i915_drm.h
index cfa3f93a..c5819953 100644
--- a/shared-core/i915_drm.h
+++ b/shared-core/i915_drm.h
@@ -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,
@@ -63,7 +63,7 @@ typedef struct _drm_i915_init {
unsigned int chipset;
} drm_i915_init_t;
-typedef struct _drm_i915_sarea {
+typedef struct drm_i915_sarea {
struct drm_tex_region texList[I915_NR_TEX_REGIONS + 1];
int last_upload; /* last time texture was uploaded */
int last_enqueue; /* last time a buffer was enqueued */
@@ -196,7 +196,7 @@ typedef struct drm_i915_flip {
/* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware.
*/
-typedef struct _drm_i915_batchbuffer {
+typedef struct drm_i915_batchbuffer {
int start; /* agp offset */
int used; /* nr bytes in use */
int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */
@@ -208,7 +208,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 */
@@ -359,7 +359,7 @@ struct drm_i915_op_arg {
struct drm_i915_execbuffer {
uint64_t ops_list;
uint32_t num_buffers;
- struct _drm_i915_batchbuffer batch;
+ struct drm_i915_batchbuffer batch;
drm_context_t context; /* for lockless use in the future */
struct drm_fence_arg fence_arg;
};
diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h
index bdc78410..d9e86de9 100644
--- a/shared-core/i915_drv.h
+++ b/shared-core/i915_drv.h
@@ -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,26 @@ 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;
+};
-typedef struct drm_i915_private {
+struct drm_i915_private {
+ struct drm_buffer_object *ring_buffer;
drm_local_map_t *sarea;
drm_local_map_t *mmio_map;
- drm_i915_sarea_t *sarea_priv;
- drm_i915_ring_buffer_t ring;
+ unsigned long mmiobase;
+ unsigned long mmiolen;
+
+ struct drm_i915_sarea *sarea_priv;
+ struct drm_i915_ring_buffer ring;
- drm_dma_handle_t *status_page_dmah;
+ struct drm_dma_handle *status_page_dmah;
void *hw_status_page;
dma_addr_t dma_status_page;
uint32_t counter;
@@ -144,10 +148,15 @@ typedef struct drm_i915_private {
#endif
DRM_SPINTYPE swaps_lock;
- drm_i915_vbl_swap_t vbl_swaps;
+ struct drm_i915_vbl_swap vbl_swaps;
unsigned int swaps_pending;
- /* Register state */
+ /* LVDS info */
+ int backlight_duty_cycle; /* restore backlight to this value */
+ bool panel_wants_dither;
+ struct drm_display_mode *panel_fixed_mode;
+
+ /* Register state */
u8 saveLBB;
u32 saveDSPACNTR;
u32 saveDSPBCNTR;
@@ -225,7 +234,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,
@@ -240,7 +249,7 @@ extern int i915_max_ioctl;
/* 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);
@@ -251,6 +260,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,
@@ -258,6 +269,7 @@ extern int i915_irq_emit(struct drm_device *dev, void *data,
extern int i915_irq_wait(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+extern void i915_driver_wait_next_vblank(struct drm_device *dev, int pipe);
extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence);
extern int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence);
extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
@@ -268,9 +280,10 @@ extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
struct drm_file *file_priv);
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_user_irq_on(drm_i915_private_t *dev_priv);
-extern void i915_user_irq_off(drm_i915_private_t *dev_priv);
+extern int i915_emit_irq(struct drm_device * dev);
+extern void i915_user_irq_on(struct drm_i915_private *dev_priv);
+extern void i915_user_irq_off(struct drm_i915_private *dev_priv);
+extern void i915_enable_interrupt (struct drm_device *dev);
extern int i915_vblank_swap(struct drm_device *dev, void *data,
struct drm_file *file_priv);
@@ -321,6 +334,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))
@@ -358,8 +377,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
@@ -426,6 +468,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 */
@@ -476,6 +520,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
@@ -484,6 +585,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
@@ -640,8 +743,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)
@@ -683,6 +792,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.
@@ -1122,13 +1232,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.
@@ -1145,6 +1259,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
index 00000000..3b43c722
--- /dev/null
+++ b/shared-core/i915_init.c
@@ -0,0 +1,329 @@
+/*
+ * 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;
+ unsigned long sareapage;
+ 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)) {
+ 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_READ_ONLY|_DRM_DRIVER, &dev_priv->mmio_map);
+ if (ret != 0) {
+ DRM_ERROR("Cannot add mapping for MMIO registers\n");
+ return ret;
+ }
+
+ /* prebuild the SAREA */
+ sareapage = max(SAREA_MAX, PAGE_SIZE);
+ ret = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK|_DRM_DRIVER,
+ &dev_priv->sarea);
+ if (ret) {
+ DRM_ERROR("SAREA setup failed\n");
+ return ret;
+ }
+
+ init_waitqueue_head(&dev->lock.lock_queue);
+
+ /* FIXME: assume sarea_priv is right after SAREA */
+ dev_priv->sarea_priv = dev_priv->sarea->handle + sizeof(struct drm_sarea);
+
+ /*
+ * Initialize the memory manager for local and AGP space
+ */
+ drm_bo_driver_init(dev);
+
+ 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);
+ drm_bo_init_mm(dev, DRM_BO_MEM_TT, prealloc_size >> PAGE_SHIFT, (agp_size - prealloc_size) >> PAGE_SHIFT);
+
+ 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, 0, 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);
+
+ dev_priv->sarea_priv->pf_current_page = 0;
+
+ 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");
+
+ intel_modeset_init(dev);
+ drm_initial_config(dev, false);
+
+ return 0;
+}
+
+int i915_driver_unload(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->ring.virtual_start) {
+ drm_core_ioremapfree(&dev_priv->ring.map, dev);
+ }
+
+ 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);
+ }
+
+ I915_WRITE(LP_RING + RING_LEN, 0);
+
+ intel_modeset_cleanup(dev);
+
+ 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)) {
+ DRM_ERROR("Memory manager type 3 not clean. "
+ "Delaying takedown\n");
+ }
+ if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM)) {
+ DRM_ERROR("Memory manager type 3 not clean. "
+ "Delaying takedown\n");
+ }
+ mutex_unlock(&dev->struct_mutex);
+
+ drm_bo_driver_finish(dev);
+
+ DRM_DEBUG("%p, %p\n", dev_priv->mmio_map, dev_priv->sarea);
+ drm_rmmap(dev, dev_priv->mmio_map);
+ drm_rmmap(dev, dev_priv->sarea);
+
+ drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
+
+ dev->dev_private = NULL;
+ return 0;
+}
+
+void i915_driver_lastclose(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ i915_do_cleanup_pageflip(dev);
+ //i915_mem_takedown(&(dev_priv->agp_heap));
+ i915_dma_cleanup(dev);
+}
+
+void i915_driver_preclose(struct drm_device *dev, struct drm_file *filp)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ //i915_mem_release(dev, filp, dev_priv->agp_heap);
+}
+
diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c
index ee7c40b5..4312eae2 100644
--- a/shared-core/i915_irq.c
+++ b/shared-core/i915_irq.c
@@ -49,7 +49,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);
@@ -66,8 +66,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_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
+ struct drm_i915_sarea *sarea_priv = dev_priv->sarea_priv;
u16 x1, y1, x2, y2;
int pf_planes = 1 << plane;
@@ -111,13 +111,13 @@ 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 list_head *list, *tmp, hits, *hit;
int nhits, nrects, slice[2], upper[2], lower[2], i, num_pages;
unsigned counter[2] = { atomic_read(&dev->vbl_received),
atomic_read(&dev->vbl_received2) };
struct drm_drawable_info *drw;
- drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
+ struct drm_i915_sarea *sarea_priv = dev_priv->sarea_priv;
u32 cpp = dev_priv->cpp, offsets[3];
u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
XY_SRC_COPY_BLT_WRITE_ALPHA |
@@ -142,8 +142,8 @@ 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))
@@ -165,8 +165,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);
@@ -223,8 +223,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;
@@ -292,8 +292,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);
@@ -304,7 +304,7 @@ static void i915_vblank_tasklet(struct drm_device *dev)
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;
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
u16 temp;
u32 pipea_stats, pipeb_stats;
@@ -367,7 +367,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
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);
@@ -384,7 +385,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)){
@@ -394,8 +395,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)) {
@@ -408,7 +409,7 @@ 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;
int ret = 0;
DRM_DEBUG("%s irq_nr=%d breadcrumb=%d\n", __FUNCTION__, irq_nr,
@@ -436,7 +437,7 @@ static int i915_driver_vblank_do_wait(struct drm_device *dev,
unsigned int *sequence,
atomic_t *counter)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = dev->dev_private;
unsigned int cur_vblank;
int ret = 0;
@@ -454,6 +455,19 @@ static int i915_driver_vblank_do_wait(struct drm_device *dev,
return ret;
}
+void i915_driver_wait_next_vblank(struct drm_device *dev, int pipe)
+{
+ unsigned int seq;
+
+ seq = pipe ? atomic_read(&dev->vbl_received2) + 1 :
+ atomic_read(&dev->vbl_received) + 1;
+
+ if (!pipe)
+ i915_driver_vblank_do_wait(dev, &seq, &dev->vbl_received);
+ else
+ i915_driver_vblank_do_wait(dev, &seq, &dev->vbl_received2);
+}
+
int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence)
{
atomic_t *counter;
@@ -482,8 +496,8 @@ int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
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);
@@ -508,8 +522,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("%s called with no initialization\n", __FUNCTION__);
@@ -519,11 +533,12 @@ int i915_irq_wait(struct drm_device *dev, void *data,
return i915_wait_irq(dev, irqwait->irq_seq);
}
-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;
+
+ dev_priv->irq_enable_reg = USER_INT_FLAG;
- dev_priv->irq_enable_reg = USER_INT_FLAG;
if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
dev_priv->irq_enable_reg |= VSYNC_PIPEA_FLAG;
if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
@@ -538,8 +553,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("%s called with no initialization\n", __FUNCTION__);
@@ -562,8 +577,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) {
@@ -587,9 +602,9 @@ 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_vblank_swap *swap = data;
+ struct drm_i915_vbl_swap *vbl_swap;
unsigned int pipe, seqtype, curseq, plane;
unsigned long irqflags;
struct list_head *list;
@@ -681,7 +696,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 &&
@@ -731,7 +746,7 @@ 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);
@@ -740,7 +755,7 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
void 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;
DRM_SPININIT(&dev_priv->swaps_lock, "swap");
INIT_LIST_HEAD(&dev_priv->vbl_swaps.head);
@@ -761,7 +776,7 @@ void 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;
+ struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private;
u16 temp;
if (!dev_priv)
diff --git a/shared-core/i915_mem.c b/shared-core/i915_mem.c
index d360896f..4c7ced24 100644
--- a/shared-core/i915_mem.c
+++ b/shared-core/i915_mem.c
@@ -45,8 +45,8 @@
*/
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_sarea *sarea_priv = dev_priv->sarea_priv;
struct drm_tex_region *list;
unsigned shift, nr;
unsigned start;
@@ -256,7 +256,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 +271,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 +309,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 +337,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 +361,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 ) {
diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c
index fc1fe07a..c2863346 100644
--- a/shared-core/radeon_cp.c
+++ b/shared-core/radeon_cp.c
@@ -1405,6 +1405,28 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
}
}
+void radeon_gart_flush(struct drm_device *dev)
+{
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+
+ if (dev_priv->flags & RADEON_IS_IGPGART) {
+ RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH);
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x1);
+ RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH);
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x0);
+ } else if (dev_priv->flags & RADEON_IS_PCIE) {
+ u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL);
+ tmp |= RADEON_PCIE_TX_GART_INVALIDATE_TLB;
+ RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp);
+ tmp &= ~RADEON_PCIE_TX_GART_INVALIDATE_TLB;
+ RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp);
+ } else {
+
+
+ }
+
+}
+
static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -2316,6 +2338,9 @@ int radeon_driver_firstopen(struct drm_device *dev)
if (ret != 0)
return ret;
+#ifdef RADEON_HAVE_BUFFER
+ drm_bo_driver_init(dev);
+#endif
return 0;
}
diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h
index 0971f970..67536c26 100644
--- a/shared-core/radeon_drm.h
+++ b/shared-core/radeon_drm.h
@@ -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_drv.h b/shared-core/radeon_drv.h
index fcbdc2e2..37b9c43f 100644
--- a/shared-core/radeon_drv.h
+++ b/shared-core/radeon_drv.h
@@ -104,6 +104,11 @@
#define DRIVER_MINOR 28
#define DRIVER_PATCHLEVEL 0
+#if defined(__linux__)
+#define RADEON_HAVE_FENCE
+#define RADEON_HAVE_BUFFER
+#endif
+
/*
* Radeon chip families
*/
@@ -284,8 +289,9 @@ typedef struct drm_radeon_private {
struct mem_block *fb_heap;
/* SW interrupt */
- wait_queue_head_t swi_queue;
- atomic_t swi_emitted;
+ wait_queue_head_t irq_queue;
+ int counter;
+
int vblank_crtc;
uint32_t irq_enable_reg;
int irq_enabled;
@@ -345,6 +351,7 @@ extern int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file
extern int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern int radeon_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern int radeon_cp_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern void radeon_gart_flush(struct drm_device *dev);
extern u32 radeon_read_fb_location(drm_radeon_private_t *dev_priv);
extern void radeon_freelist_reset(struct drm_device * dev);
@@ -364,6 +371,7 @@ extern void radeon_mem_release(struct drm_file *file_priv,
/* radeon_irq.c */
extern int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_priv);
extern int radeon_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int radeon_emit_irq(struct drm_device * dev);
extern void radeon_do_release(struct drm_device * dev);
extern int radeon_driver_vblank_wait(struct drm_device * dev,
@@ -397,6 +405,30 @@ extern int r300_do_cp_cmdbuf(struct drm_device *dev,
struct drm_file *file_priv,
drm_radeon_kcmd_buffer_t *cmdbuf);
+
+#ifdef RADEON_HAVE_FENCE
+/* i915_fence.c */
+
+
+extern void radeon_fence_handler(struct drm_device *dev);
+extern int radeon_fence_emit_sequence(struct drm_device *dev, uint32_t class,
+ uint32_t flags, uint32_t *sequence,
+ uint32_t *native_type);
+extern void radeon_poke_flush(struct drm_device *dev, uint32_t class);
+extern int radeon_fence_has_irq(struct drm_device *dev, uint32_t class, uint32_t flags);
+#endif
+
+#ifdef RADEON_HAVE_BUFFER
+/* radeon_buffer.c */
+extern struct drm_ttm_backend *radeon_create_ttm_backend_entry(struct drm_device *dev);
+extern int radeon_fence_types(struct drm_buffer_object *bo, uint32_t *class, uint32_t *type);
+extern int radeon_invalidate_caches(struct drm_device *dev, uint64_t buffer_flags);
+extern uint32_t radeon_evict_mask(struct drm_buffer_object *bo);
+extern int radeon_init_mem_type(struct drm_device * dev, uint32_t type,
+ struct drm_mem_type_manager * man);
+extern int radeon_move(struct drm_buffer_object * bo,
+ int evict, int no_wait, struct drm_bo_mem_reg * new_mem);
+#endif
/* Flags for stats.boxes
*/
#define RADEON_BOX_DMA_IDLE 0x1
@@ -1268,4 +1300,19 @@ do { \
write &= mask; \
} while (0)
+/* Breadcrumb - swi irq */
+#define READ_BREADCRUMB(dev_priv) RADEON_READ(RADEON_LAST_SWI_REG)
+
+static inline int radeon_update_breadcrumb(struct drm_device *dev)
+{
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+
+ dev_priv->sarea_priv->last_fence = ++dev_priv->counter;
+
+ if (dev_priv->counter > 0x7FFFFFFFUL)
+ dev_priv->sarea_priv->last_fence = dev_priv->counter = 1;
+
+ return dev_priv->counter;
+}
+
#endif /* __RADEON_DRV_H__ */
diff --git a/shared-core/radeon_irq.c b/shared-core/radeon_irq.c
index 2b2407ee..544e3a0f 100644
--- a/shared-core/radeon_irq.c
+++ b/shared-core/radeon_irq.c
@@ -82,7 +82,10 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
/* SW interrupt */
if (stat & RADEON_SW_INT_TEST) {
- DRM_WAKEUP(&dev_priv->swi_queue);
+ DRM_WAKEUP(&dev_priv->irq_queue);
+#ifdef RADEON_HAVE_FENCE
+ radeon_fence_handler(dev);
+#endif
}
/* VBLANK interrupt */
@@ -109,14 +112,13 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
return IRQ_HANDLED;
}
-static int radeon_emit_irq(struct drm_device * dev)
+int radeon_emit_irq(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
unsigned int ret;
RING_LOCALS;
- atomic_inc(&dev_priv->swi_emitted);
- ret = atomic_read(&dev_priv->swi_emitted);
+ ret = radeon_update_breadcrumb(dev);
BEGIN_RING(4);
OUT_RING_REG(RADEON_LAST_SWI_REG, ret);
@@ -133,13 +135,13 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr)
(drm_radeon_private_t *) dev->dev_private;
int ret = 0;
- if (RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr)
+ if (READ_BREADCRUMB(dev_priv) >= swi_nr)
return 0;
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
- DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * DRM_HZ,
- RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr);
+ DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
+ READ_BREADCRUMB(dev_priv) >= swi_nr);
return ret;
}
@@ -270,8 +272,8 @@ void radeon_driver_irq_postinstall(struct drm_device * dev)
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
- atomic_set(&dev_priv->swi_emitted, 0);
- DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
+ dev_priv->counter = 0;
+ DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
radeon_enable_interrupt(dev);
}
diff --git a/shared-core/radeon_ms.h b/shared-core/radeon_ms.h
new file mode 100644
index 00000000..ee795f3a
--- /dev/null
+++ b/shared-core/radeon_ms.h
@@ -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"
+
+#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
+
+#define RADEON_PAGE_SIZE 4096
+#define RADEON_MAX_CONNECTORS 8
+#define RADEON_MAX_OUTPUTS 8
+
+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_ms_properties {
+ uint16_t subvendor;
+ uint16_t subdevice;
+ int16_t pll_reference_freq;
+ 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];
+};
+
+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_properties *properties;
+ 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;
+};
+
+
+/* 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);
+uint32_t radeon_ms_evict_mask(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_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);
+void 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);
+void radeon_ms_outputs_destroy(struct drm_device *dev);
+int radeon_ms_outputs_from_properties(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_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
index 00000000..cedad689
--- /dev/null
+++ b/shared-core/radeon_ms_bo.c
@@ -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.mask = 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_bind_ttm(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;
+}
+
+uint32_t radeon_ms_evict_mask(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
index 00000000..d50c9fb8
--- /dev/null
+++ b/shared-core/radeon_ms_bus.c
@@ -0,0 +1,453 @@
+/*
+ * 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;
+ 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);
+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];
+ /* 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 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_cp.c b/shared-core/radeon_ms_cp.c
new file mode 100644
index 00000000..c01769bd
--- /dev/null
+++ b/shared-core/radeon_ms_cp.c
@@ -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
index 00000000..f0397d87
--- /dev/null
+++ b/shared-core/radeon_ms_cp_mc.c
@@ -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
index 00000000..fe89e5e4
--- /dev/null
+++ b/shared-core/radeon_ms_crtc.c
@@ -0,0 +1,800 @@
+/*
+ * 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(int clock, int rdiv,
+ int fdiv, int pdiv,
+ int rfrq, int pfrq)
+{
+ int dfrq;
+
+ if (rdiv < 2 || fdiv < 4) {
+ return 0;
+ }
+ dfrq = rfrq / rdiv;
+ if (dfrq < 2000 || dfrq > 3300) {
+ return 0;
+ }
+ if (pfrq < 125000 || pfrq > 250000) {
+ 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(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->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
index 00000000..297623a0
--- /dev/null
+++ b/shared-core/radeon_ms_dac.c
@@ -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
index 00000000..8d0481e1
--- /dev/null
+++ b/shared-core/radeon_ms_drm.c
@@ -0,0 +1,298 @@
+/*
+ * 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_mask = radeon_ms_evict_mask,
+ .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);
+ 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);
+ 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_properties(dev);
+ if (ret != 0) {
+ radeon_ms_driver_unload(dev);
+ return ret;
+ }
+ ret = radeon_ms_connectors_from_properties(dev);
+ if (ret != 0) {
+ radeon_ms_driver_unload(dev);
+ return 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)) {
+ 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)) {
+ 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
index 00000000..842d5331
--- /dev/null
+++ b/shared-core/radeon_ms_drm.h
@@ -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
index 00000000..b2ce3cbb
--- /dev/null
+++ b/shared-core/radeon_ms_exec.c
@@ -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
index 00000000..779595d6
--- /dev/null
+++ b/shared-core/radeon_ms_family.c
@@ -0,0 +1,229 @@
+/*
+ * 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"
+
+static 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
+};
+
+static 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
+};
+
+static 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"
+};
+
+static 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"
+};
+
+static struct radeon_ms_properties properties[] = {
+ /* default only one VGA connector */
+ {
+ 0, 0, 27000, 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
+ }
+ },
+ {
+ 0x1043, 0x176, 27000, 25000, 200000, 1, 1, 1, 1,
+ {
+ &radeon_ms_dac1, &radeon_ms_dac2, NULL, NULL, NULL,
+ NULL, NULL, NULL
+ },
+ {
+ &radeon_ms_vga, &radeon_ms_dvi_i_2, NULL, NULL, NULL,
+ NULL, NULL, NULL
+ }
+ },
+ {
+ 0x1002, 0x4150, 27000, 25000, 200000, 1, 1, 1, 1,
+ {
+ &radeon_ms_dac1, &radeon_ms_dac2, NULL, NULL, NULL,
+ NULL, NULL, NULL
+ },
+ {
+ &radeon_ms_vga, &radeon_ms_dvi_i_2, NULL, NULL, NULL,
+ NULL, NULL, NULL
+ }
+ },
+};
+
+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 i;
+
+ 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;
+ }
+ dev_priv->properties = NULL;
+ 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);
+ dev_priv->properties = &properties[i];
+ }
+ }
+ if (dev_priv->properties == NULL) {
+ dev_priv->properties = &properties[0];
+ }
+ return 0;
+}
diff --git a/shared-core/radeon_ms_fence.c b/shared-core/radeon_ms_fence.c
new file mode 100644
index 00000000..6fcf5437
--- /dev/null
+++ b/shared-core/radeon_ms_fence.c
@@ -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
index 00000000..28683781
--- /dev/null
+++ b/shared-core/radeon_ms_gpu.c
@@ -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
index 00000000..1801c496
--- /dev/null
+++ b/shared-core/radeon_ms_i2c.c
@@ -0,0 +1,279 @@
+/*
+ * 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;
+ 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;
+ 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;
+ 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;
+ 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\n",
+ i2c->adapter.name);
+ goto out_free;
+ }
+ DRM_INFO("[radeon_ms] registered I2C '%s' bus\n", i2c->adapter.name);
+ 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
index 00000000..24182c75
--- /dev/null
+++ b/shared-core/radeon_ms_irq.c
@@ -0,0 +1,160 @@
+/*
+ * 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);
+}
+
+void radeon_ms_irq_postinstall(struct drm_device * dev)
+{
+ radeon_ms_irq_enable(dev);
+}
+
+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
index 00000000..35e5c376
--- /dev/null
+++ b/shared-core/radeon_ms_output.c
@@ -0,0 +1,337 @@
+/*
+ * 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;
+}
+
+static 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;
+
+ 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->name);
+ if (output == NULL) {
+ radeon_ms_connectors_destroy(dev);
+ return -EINVAL;
+ }
+ connector->output = output;
+ output->driver_private = connector;
+ output->possible_crtcs = 0x3;
+ dev_priv->connectors[i] = connector;
+ }
+ }
+ 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;
+
+ 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]);
+ }
+ }
+ 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_reg.h b/shared-core/radeon_ms_reg.h
new file mode 100644
index 00000000..d450280c
--- /dev/null
+++ b/shared-core/radeon_ms_reg.h
@@ -0,0 +1,1655 @@
+/*
+ * 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 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_state.c b/shared-core/radeon_ms_state.c
new file mode 100644
index 00000000..17f8b764
--- /dev/null
+++ b/shared-core/radeon_ms_state.c
@@ -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);
+}
diff --git a/tests/mode/Makefile b/tests/mode/Makefile
new file mode 100644
index 00000000..a3d3b49a
--- /dev/null
+++ b/tests/mode/Makefile
@@ -0,0 +1,11 @@
+
+all: modetest
+
+#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \
+# -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \
+
+modetest: modetest.c
+ @gcc $(CFLAGS) -o modetest -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm modetest.c
+
+clean:
+ @rm -f modetest
diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c
new file mode 100644
index 00000000..f1fe64df
--- /dev/null
+++ b/tests/mode/modetest.c
@@ -0,0 +1,373 @@
+
+#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: %s\n", output->name);
+ 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 = 1;
+ if (ret)
+ goto err;
+
+ printf("\tAdding FB\n");
+ ret = drmModeAddFB(fd, 640, 480, 32, 8, 0, &bo, &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;
+ const char *driver = "i915"; /* hardcoded for now */
+ drmModeResPtr res;
+
+ printf("Starting test\n");
+
+ fd = drmOpen(driver, NULL);
+
+ if (fd < 0) {
+ printf("Failed to open the card fb\n");
+ 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
index 00000000..fa155f4e
--- /dev/null
+++ b/tests/mode/test
@@ -0,0 +1 @@
+LD_PRELOAD=../../libdrm/.libs/libdrm.so ./modetest