ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/linux/drivers/gpu/drm/r128/Makefile b/marvell/linux/drivers/gpu/drm/r128/Makefile
new file mode 100644
index 0000000..ae8a186
--- /dev/null
+++ b/marvell/linux/drivers/gpu/drm/r128/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+r128-y   := r128_drv.o r128_cce.o r128_state.o r128_irq.o
+
+r128-$(CONFIG_COMPAT)   += r128_ioc32.o
+
+obj-$(CONFIG_DRM_R128)	+= r128.o
diff --git a/marvell/linux/drivers/gpu/drm/r128/r128_cce.c b/marvell/linux/drivers/gpu/drm/r128/r128_cce.c
new file mode 100644
index 0000000..138af32
--- /dev/null
+++ b/marvell/linux/drivers/gpu/drm/r128/r128_cce.c
@@ -0,0 +1,945 @@
+/* r128_cce.c -- ATI Rage 128 driver -*- linux-c -*-
+ * Created: Wed Apr  5 19:24:19 2000 by kevin@precisioninsight.com
+ */
+/*
+ * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * 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:
+ *    Gareth Hughes <gareth@valinux.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include <drm/drm_agpsupport.h>
+#include <drm/drm_device.h>
+#include <drm/drm_file.h>
+#include <drm/drm_irq.h>
+#include <drm/drm_print.h>
+#include <drm/r128_drm.h>
+
+#include "r128_drv.h"
+
+#define R128_FIFO_DEBUG		0
+
+#define FIRMWARE_NAME		"r128/r128_cce.bin"
+
+MODULE_FIRMWARE(FIRMWARE_NAME);
+
+static int R128_READ_PLL(struct drm_device *dev, int addr)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+
+	R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f);
+	return R128_READ(R128_CLOCK_CNTL_DATA);
+}
+
+#if R128_FIFO_DEBUG
+static void r128_status(drm_r128_private_t *dev_priv)
+{
+	printk("GUI_STAT           = 0x%08x\n",
+	       (unsigned int)R128_READ(R128_GUI_STAT));
+	printk("PM4_STAT           = 0x%08x\n",
+	       (unsigned int)R128_READ(R128_PM4_STAT));
+	printk("PM4_BUFFER_DL_WPTR = 0x%08x\n",
+	       (unsigned int)R128_READ(R128_PM4_BUFFER_DL_WPTR));
+	printk("PM4_BUFFER_DL_RPTR = 0x%08x\n",
+	       (unsigned int)R128_READ(R128_PM4_BUFFER_DL_RPTR));
+	printk("PM4_MICRO_CNTL     = 0x%08x\n",
+	       (unsigned int)R128_READ(R128_PM4_MICRO_CNTL));
+	printk("PM4_BUFFER_CNTL    = 0x%08x\n",
+	       (unsigned int)R128_READ(R128_PM4_BUFFER_CNTL));
+}
+#endif
+
+/* ================================================================
+ * Engine, FIFO control
+ */
+
+static int r128_do_pixcache_flush(drm_r128_private_t *dev_priv)
+{
+	u32 tmp;
+	int i;
+
+	tmp = R128_READ(R128_PC_NGUI_CTLSTAT) | R128_PC_FLUSH_ALL;
+	R128_WRITE(R128_PC_NGUI_CTLSTAT, tmp);
+
+	for (i = 0; i < dev_priv->usec_timeout; i++) {
+		if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY))
+			return 0;
+		udelay(1);
+	}
+
+#if R128_FIFO_DEBUG
+	DRM_ERROR("failed!\n");
+#endif
+	return -EBUSY;
+}
+
+static int r128_do_wait_for_fifo(drm_r128_private_t *dev_priv, int entries)
+{
+	int i;
+
+	for (i = 0; i < dev_priv->usec_timeout; i++) {
+		int slots = R128_READ(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK;
+		if (slots >= entries)
+			return 0;
+		udelay(1);
+	}
+
+#if R128_FIFO_DEBUG
+	DRM_ERROR("failed!\n");
+#endif
+	return -EBUSY;
+}
+
+static int r128_do_wait_for_idle(drm_r128_private_t *dev_priv)
+{
+	int i, ret;
+
+	ret = r128_do_wait_for_fifo(dev_priv, 64);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < dev_priv->usec_timeout; i++) {
+		if (!(R128_READ(R128_GUI_STAT) & R128_GUI_ACTIVE)) {
+			r128_do_pixcache_flush(dev_priv);
+			return 0;
+		}
+		udelay(1);
+	}
+
+#if R128_FIFO_DEBUG
+	DRM_ERROR("failed!\n");
+#endif
+	return -EBUSY;
+}
+
+/* ================================================================
+ * CCE control, initialization
+ */
+
+/* Load the microcode for the CCE */
+static int r128_cce_load_microcode(drm_r128_private_t *dev_priv)
+{
+	struct platform_device *pdev;
+	const struct firmware *fw;
+	const __be32 *fw_data;
+	int rc, i;
+
+	DRM_DEBUG("\n");
+
+	pdev = platform_device_register_simple("r128_cce", 0, NULL, 0);
+	if (IS_ERR(pdev)) {
+		pr_err("r128_cce: Failed to register firmware\n");
+		return PTR_ERR(pdev);
+	}
+	rc = request_firmware(&fw, FIRMWARE_NAME, &pdev->dev);
+	platform_device_unregister(pdev);
+	if (rc) {
+		pr_err("r128_cce: Failed to load firmware \"%s\"\n",
+		       FIRMWARE_NAME);
+		return rc;
+	}
+
+	if (fw->size != 256 * 8) {
+		pr_err("r128_cce: Bogus length %zu in firmware \"%s\"\n",
+		       fw->size, FIRMWARE_NAME);
+		rc = -EINVAL;
+		goto out_release;
+	}
+
+	r128_do_wait_for_idle(dev_priv);
+
+	fw_data = (const __be32 *)fw->data;
+	R128_WRITE(R128_PM4_MICROCODE_ADDR, 0);
+	for (i = 0; i < 256; i++) {
+		R128_WRITE(R128_PM4_MICROCODE_DATAH,
+			   be32_to_cpup(&fw_data[i * 2]));
+		R128_WRITE(R128_PM4_MICROCODE_DATAL,
+			   be32_to_cpup(&fw_data[i * 2 + 1]));
+	}
+
+out_release:
+	release_firmware(fw);
+	return rc;
+}
+
+/* Flush any pending commands to the CCE.  This should only be used just
+ * prior to a wait for idle, as it informs the engine that the command
+ * stream is ending.
+ */
+static void r128_do_cce_flush(drm_r128_private_t *dev_priv)
+{
+	u32 tmp;
+
+	tmp = R128_READ(R128_PM4_BUFFER_DL_WPTR) | R128_PM4_BUFFER_DL_DONE;
+	R128_WRITE(R128_PM4_BUFFER_DL_WPTR, tmp);
+}
+
+/* Wait for the CCE to go idle.
+ */
+int r128_do_cce_idle(drm_r128_private_t *dev_priv)
+{
+	int i;
+
+	for (i = 0; i < dev_priv->usec_timeout; i++) {
+		if (GET_RING_HEAD(dev_priv) == dev_priv->ring.tail) {
+			int pm4stat = R128_READ(R128_PM4_STAT);
+			if (((pm4stat & R128_PM4_FIFOCNT_MASK) >=
+			     dev_priv->cce_fifo_size) &&
+			    !(pm4stat & (R128_PM4_BUSY |
+					 R128_PM4_GUI_ACTIVE))) {
+				return r128_do_pixcache_flush(dev_priv);
+			}
+		}
+		udelay(1);
+	}
+
+#if R128_FIFO_DEBUG
+	DRM_ERROR("failed!\n");
+	r128_status(dev_priv);
+#endif
+	return -EBUSY;
+}
+
+/* Start the Concurrent Command Engine.
+ */
+static void r128_do_cce_start(drm_r128_private_t *dev_priv)
+{
+	r128_do_wait_for_idle(dev_priv);
+
+	R128_WRITE(R128_PM4_BUFFER_CNTL,
+		   dev_priv->cce_mode | dev_priv->ring.size_l2qw
+		   | R128_PM4_BUFFER_CNTL_NOUPDATE);
+	R128_READ(R128_PM4_BUFFER_ADDR);	/* as per the sample code */
+	R128_WRITE(R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN);
+
+	dev_priv->cce_running = 1;
+}
+
+/* Reset the Concurrent Command Engine.  This will not flush any pending
+ * commands, so you must wait for the CCE command stream to complete
+ * before calling this routine.
+ */
+static void r128_do_cce_reset(drm_r128_private_t *dev_priv)
+{
+	R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0);
+	R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0);
+	dev_priv->ring.tail = 0;
+}
+
+/* Stop the Concurrent Command Engine.  This will not flush any pending
+ * commands, so you must flush the command stream and wait for the CCE
+ * to go idle before calling this routine.
+ */
+static void r128_do_cce_stop(drm_r128_private_t *dev_priv)
+{
+	R128_WRITE(R128_PM4_MICRO_CNTL, 0);
+	R128_WRITE(R128_PM4_BUFFER_CNTL,
+		   R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE);
+
+	dev_priv->cce_running = 0;
+}
+
+/* Reset the engine.  This will stop the CCE if it is running.
+ */
+static int r128_do_engine_reset(struct drm_device *dev)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	u32 clock_cntl_index, mclk_cntl, gen_reset_cntl;
+
+	r128_do_pixcache_flush(dev_priv);
+
+	clock_cntl_index = R128_READ(R128_CLOCK_CNTL_INDEX);
+	mclk_cntl = R128_READ_PLL(dev, R128_MCLK_CNTL);
+
+	R128_WRITE_PLL(R128_MCLK_CNTL,
+		       mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP);
+
+	gen_reset_cntl = R128_READ(R128_GEN_RESET_CNTL);
+
+	/* Taken from the sample code - do not change */
+	R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl | R128_SOFT_RESET_GUI);
+	R128_READ(R128_GEN_RESET_CNTL);
+	R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl & ~R128_SOFT_RESET_GUI);
+	R128_READ(R128_GEN_RESET_CNTL);
+
+	R128_WRITE_PLL(R128_MCLK_CNTL, mclk_cntl);
+	R128_WRITE(R128_CLOCK_CNTL_INDEX, clock_cntl_index);
+	R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl);
+
+	/* Reset the CCE ring */
+	r128_do_cce_reset(dev_priv);
+
+	/* The CCE is no longer running after an engine reset */
+	dev_priv->cce_running = 0;
+
+	/* Reset any pending vertex, indirect buffers */
+	r128_freelist_reset(dev);
+
+	return 0;
+}
+
+static void r128_cce_init_ring_buffer(struct drm_device *dev,
+				      drm_r128_private_t *dev_priv)
+{
+	u32 ring_start;
+	u32 tmp;
+
+	DRM_DEBUG("\n");
+
+	/* The manual (p. 2) says this address is in "VM space".  This
+	 * means it's an offset from the start of AGP space.
+	 */
+#if IS_ENABLED(CONFIG_AGP)
+	if (!dev_priv->is_pci)
+		ring_start = dev_priv->cce_ring->offset - dev->agp->base;
+	else
+#endif
+		ring_start = dev_priv->cce_ring->offset -
+		    (unsigned long)dev->sg->virtual;
+
+	R128_WRITE(R128_PM4_BUFFER_OFFSET, ring_start | R128_AGP_OFFSET);
+
+	R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0);
+	R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0);
+
+	/* Set watermark control */
+	R128_WRITE(R128_PM4_BUFFER_WM_CNTL,
+		   ((R128_WATERMARK_L / 4) << R128_WMA_SHIFT)
+		   | ((R128_WATERMARK_M / 4) << R128_WMB_SHIFT)
+		   | ((R128_WATERMARK_N / 4) << R128_WMC_SHIFT)
+		   | ((R128_WATERMARK_K / 64) << R128_WB_WM_SHIFT));
+
+	/* Force read.  Why?  Because it's in the examples... */
+	R128_READ(R128_PM4_BUFFER_ADDR);
+
+	/* Turn on bus mastering */
+	tmp = R128_READ(R128_BUS_CNTL) & ~R128_BUS_MASTER_DIS;
+	R128_WRITE(R128_BUS_CNTL, tmp);
+}
+
+static int r128_do_init_cce(struct drm_device *dev, drm_r128_init_t *init)
+{
+	drm_r128_private_t *dev_priv;
+	int rc;
+
+	DRM_DEBUG("\n");
+
+	if (dev->dev_private) {
+		DRM_DEBUG("called when already initialized\n");
+		return -EINVAL;
+	}
+
+	dev_priv = kzalloc(sizeof(drm_r128_private_t), GFP_KERNEL);
+	if (dev_priv == NULL)
+		return -ENOMEM;
+
+	dev_priv->is_pci = init->is_pci;
+
+	if (dev_priv->is_pci && !dev->sg) {
+		DRM_ERROR("PCI GART memory not allocated!\n");
+		dev->dev_private = (void *)dev_priv;
+		r128_do_cleanup_cce(dev);
+		return -EINVAL;
+	}
+
+	dev_priv->usec_timeout = init->usec_timeout;
+	if (dev_priv->usec_timeout < 1 ||
+	    dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT) {
+		DRM_DEBUG("TIMEOUT problem!\n");
+		dev->dev_private = (void *)dev_priv;
+		r128_do_cleanup_cce(dev);
+		return -EINVAL;
+	}
+
+	dev_priv->cce_mode = init->cce_mode;
+
+	/* GH: Simple idle check.
+	 */
+	atomic_set(&dev_priv->idle_count, 0);
+
+	/* We don't support anything other than bus-mastering ring mode,
+	 * but the ring can be in either AGP or PCI space for the ring
+	 * read pointer.
+	 */
+	if ((init->cce_mode != R128_PM4_192BM) &&
+	    (init->cce_mode != R128_PM4_128BM_64INDBM) &&
+	    (init->cce_mode != R128_PM4_64BM_128INDBM) &&
+	    (init->cce_mode != R128_PM4_64BM_64VCBM_64INDBM)) {
+		DRM_DEBUG("Bad cce_mode!\n");
+		dev->dev_private = (void *)dev_priv;
+		r128_do_cleanup_cce(dev);
+		return -EINVAL;
+	}
+
+	switch (init->cce_mode) {
+	case R128_PM4_NONPM4:
+		dev_priv->cce_fifo_size = 0;
+		break;
+	case R128_PM4_192PIO:
+	case R128_PM4_192BM:
+		dev_priv->cce_fifo_size = 192;
+		break;
+	case R128_PM4_128PIO_64INDBM:
+	case R128_PM4_128BM_64INDBM:
+		dev_priv->cce_fifo_size = 128;
+		break;
+	case R128_PM4_64PIO_128INDBM:
+	case R128_PM4_64BM_128INDBM:
+	case R128_PM4_64PIO_64VCBM_64INDBM:
+	case R128_PM4_64BM_64VCBM_64INDBM:
+	case R128_PM4_64PIO_64VCPIO_64INDPIO:
+		dev_priv->cce_fifo_size = 64;
+		break;
+	}
+
+	switch (init->fb_bpp) {
+	case 16:
+		dev_priv->color_fmt = R128_DATATYPE_RGB565;
+		break;
+	case 32:
+	default:
+		dev_priv->color_fmt = R128_DATATYPE_ARGB8888;
+		break;
+	}
+	dev_priv->front_offset = init->front_offset;
+	dev_priv->front_pitch = init->front_pitch;
+	dev_priv->back_offset = init->back_offset;
+	dev_priv->back_pitch = init->back_pitch;
+
+	switch (init->depth_bpp) {
+	case 16:
+		dev_priv->depth_fmt = R128_DATATYPE_RGB565;
+		break;
+	case 24:
+	case 32:
+	default:
+		dev_priv->depth_fmt = R128_DATATYPE_ARGB8888;
+		break;
+	}
+	dev_priv->depth_offset = init->depth_offset;
+	dev_priv->depth_pitch = init->depth_pitch;
+	dev_priv->span_offset = init->span_offset;
+
+	dev_priv->front_pitch_offset_c = (((dev_priv->front_pitch / 8) << 21) |
+					  (dev_priv->front_offset >> 5));
+	dev_priv->back_pitch_offset_c = (((dev_priv->back_pitch / 8) << 21) |
+					 (dev_priv->back_offset >> 5));
+	dev_priv->depth_pitch_offset_c = (((dev_priv->depth_pitch / 8) << 21) |
+					  (dev_priv->depth_offset >> 5) |
+					  R128_DST_TILE);
+	dev_priv->span_pitch_offset_c = (((dev_priv->depth_pitch / 8) << 21) |
+					 (dev_priv->span_offset >> 5));
+
+	dev_priv->sarea = drm_legacy_getsarea(dev);
+	if (!dev_priv->sarea) {
+		DRM_ERROR("could not find sarea!\n");
+		dev->dev_private = (void *)dev_priv;
+		r128_do_cleanup_cce(dev);
+		return -EINVAL;
+	}
+
+	dev_priv->mmio = drm_legacy_findmap(dev, init->mmio_offset);
+	if (!dev_priv->mmio) {
+		DRM_ERROR("could not find mmio region!\n");
+		dev->dev_private = (void *)dev_priv;
+		r128_do_cleanup_cce(dev);
+		return -EINVAL;
+	}
+	dev_priv->cce_ring = drm_legacy_findmap(dev, init->ring_offset);
+	if (!dev_priv->cce_ring) {
+		DRM_ERROR("could not find cce ring region!\n");
+		dev->dev_private = (void *)dev_priv;
+		r128_do_cleanup_cce(dev);
+		return -EINVAL;
+	}
+	dev_priv->ring_rptr = drm_legacy_findmap(dev, init->ring_rptr_offset);
+	if (!dev_priv->ring_rptr) {
+		DRM_ERROR("could not find ring read pointer!\n");
+		dev->dev_private = (void *)dev_priv;
+		r128_do_cleanup_cce(dev);
+		return -EINVAL;
+	}
+	dev->agp_buffer_token = init->buffers_offset;
+	dev->agp_buffer_map = drm_legacy_findmap(dev, init->buffers_offset);
+	if (!dev->agp_buffer_map) {
+		DRM_ERROR("could not find dma buffer region!\n");
+		dev->dev_private = (void *)dev_priv;
+		r128_do_cleanup_cce(dev);
+		return -EINVAL;
+	}
+
+	if (!dev_priv->is_pci) {
+		dev_priv->agp_textures =
+		    drm_legacy_findmap(dev, init->agp_textures_offset);
+		if (!dev_priv->agp_textures) {
+			DRM_ERROR("could not find agp texture region!\n");
+			dev->dev_private = (void *)dev_priv;
+			r128_do_cleanup_cce(dev);
+			return -EINVAL;
+		}
+	}
+
+	dev_priv->sarea_priv =
+	    (drm_r128_sarea_t *) ((u8 *) dev_priv->sarea->handle +
+				  init->sarea_priv_offset);
+
+#if IS_ENABLED(CONFIG_AGP)
+	if (!dev_priv->is_pci) {
+		drm_legacy_ioremap_wc(dev_priv->cce_ring, dev);
+		drm_legacy_ioremap_wc(dev_priv->ring_rptr, dev);
+		drm_legacy_ioremap_wc(dev->agp_buffer_map, dev);
+		if (!dev_priv->cce_ring->handle ||
+		    !dev_priv->ring_rptr->handle ||
+		    !dev->agp_buffer_map->handle) {
+			DRM_ERROR("Could not ioremap agp regions!\n");
+			dev->dev_private = (void *)dev_priv;
+			r128_do_cleanup_cce(dev);
+			return -ENOMEM;
+		}
+	} else
+#endif
+	{
+		dev_priv->cce_ring->handle =
+			(void *)(unsigned long)dev_priv->cce_ring->offset;
+		dev_priv->ring_rptr->handle =
+			(void *)(unsigned long)dev_priv->ring_rptr->offset;
+		dev->agp_buffer_map->handle =
+			(void *)(unsigned long)dev->agp_buffer_map->offset;
+	}
+
+#if IS_ENABLED(CONFIG_AGP)
+	if (!dev_priv->is_pci)
+		dev_priv->cce_buffers_offset = dev->agp->base;
+	else
+#endif
+		dev_priv->cce_buffers_offset = (unsigned long)dev->sg->virtual;
+
+	dev_priv->ring.start = (u32 *) dev_priv->cce_ring->handle;
+	dev_priv->ring.end = ((u32 *) dev_priv->cce_ring->handle
+			      + init->ring_size / sizeof(u32));
+	dev_priv->ring.size = init->ring_size;
+	dev_priv->ring.size_l2qw = order_base_2(init->ring_size / 8);
+
+	dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;
+
+	dev_priv->ring.high_mark = 128;
+
+	dev_priv->sarea_priv->last_frame = 0;
+	R128_WRITE(R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
+
+	dev_priv->sarea_priv->last_dispatch = 0;
+	R128_WRITE(R128_LAST_DISPATCH_REG, dev_priv->sarea_priv->last_dispatch);
+
+#if IS_ENABLED(CONFIG_AGP)
+	if (dev_priv->is_pci) {
+#endif
+		dev_priv->gart_info.table_mask = DMA_BIT_MASK(32);
+		dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN;
+		dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE;
+		dev_priv->gart_info.addr = NULL;
+		dev_priv->gart_info.bus_addr = 0;
+		dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
+		rc = drm_ati_pcigart_init(dev, &dev_priv->gart_info);
+		if (rc) {
+			DRM_ERROR("failed to init PCI GART!\n");
+			dev->dev_private = (void *)dev_priv;
+			r128_do_cleanup_cce(dev);
+			return rc;
+		}
+		R128_WRITE(R128_PCI_GART_PAGE, dev_priv->gart_info.bus_addr);
+#if IS_ENABLED(CONFIG_AGP)
+	}
+#endif
+
+	r128_cce_init_ring_buffer(dev, dev_priv);
+	rc = r128_cce_load_microcode(dev_priv);
+
+	dev->dev_private = (void *)dev_priv;
+
+	r128_do_engine_reset(dev);
+
+	if (rc) {
+		DRM_ERROR("Failed to load firmware!\n");
+		r128_do_cleanup_cce(dev);
+	}
+
+	return rc;
+}
+
+int r128_do_cleanup_cce(struct drm_device *dev)
+{
+
+	/* 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.
+	 */
+	if (dev->irq_enabled)
+		drm_irq_uninstall(dev);
+
+	if (dev->dev_private) {
+		drm_r128_private_t *dev_priv = dev->dev_private;
+
+#if IS_ENABLED(CONFIG_AGP)
+		if (!dev_priv->is_pci) {
+			if (dev_priv->cce_ring != NULL)
+				drm_legacy_ioremapfree(dev_priv->cce_ring, dev);
+			if (dev_priv->ring_rptr != NULL)
+				drm_legacy_ioremapfree(dev_priv->ring_rptr, dev);
+			if (dev->agp_buffer_map != NULL) {
+				drm_legacy_ioremapfree(dev->agp_buffer_map, dev);
+				dev->agp_buffer_map = NULL;
+			}
+		} else
+#endif
+		{
+			if (dev_priv->gart_info.bus_addr)
+				if (!drm_ati_pcigart_cleanup(dev,
+							&dev_priv->gart_info))
+					DRM_ERROR
+					    ("failed to cleanup PCI GART!\n");
+		}
+
+		kfree(dev->dev_private);
+		dev->dev_private = NULL;
+	}
+
+	return 0;
+}
+
+int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	drm_r128_init_t *init = data;
+
+	DRM_DEBUG("\n");
+
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	switch (init->func) {
+	case R128_INIT_CCE:
+		return r128_do_init_cce(dev, init);
+	case R128_CLEANUP_CCE:
+		return r128_do_cleanup_cce(dev);
+	}
+
+	return -EINVAL;
+}
+
+int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	DRM_DEBUG("\n");
+
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	DEV_INIT_TEST_WITH_RETURN(dev_priv);
+
+	if (dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4) {
+		DRM_DEBUG("while CCE running\n");
+		return 0;
+	}
+
+	r128_do_cce_start(dev_priv);
+
+	return 0;
+}
+
+/* Stop the CCE.  The engine must have been idled before calling this
+ * routine.
+ */
+int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_r128_cce_stop_t *stop = data;
+	int ret;
+	DRM_DEBUG("\n");
+
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	DEV_INIT_TEST_WITH_RETURN(dev_priv);
+
+	/* Flush any pending CCE commands.  This ensures any outstanding
+	 * commands are exectuted by the engine before we turn it off.
+	 */
+	if (stop->flush)
+		r128_do_cce_flush(dev_priv);
+
+	/* If we fail to make the engine go idle, we return an error
+	 * code so that the DRM ioctl wrapper can try again.
+	 */
+	if (stop->idle) {
+		ret = r128_do_cce_idle(dev_priv);
+		if (ret)
+			return ret;
+	}
+
+	/* Finally, we can turn off the CCE.  If the engine isn't idle,
+	 * we will get some dropped triangles as they won't be fully
+	 * rendered before the CCE is shut down.
+	 */
+	r128_do_cce_stop(dev_priv);
+
+	/* Reset the engine */
+	r128_do_engine_reset(dev);
+
+	return 0;
+}
+
+/* Just reset the CCE ring.  Called as part of an X Server engine reset.
+ */
+int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	DRM_DEBUG("\n");
+
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	DEV_INIT_TEST_WITH_RETURN(dev_priv);
+
+	r128_do_cce_reset(dev_priv);
+
+	/* The CCE is no longer running after an engine reset */
+	dev_priv->cce_running = 0;
+
+	return 0;
+}
+
+int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	DRM_DEBUG("\n");
+
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	DEV_INIT_TEST_WITH_RETURN(dev_priv);
+
+	if (dev_priv->cce_running)
+		r128_do_cce_flush(dev_priv);
+
+	return r128_do_cce_idle(dev_priv);
+}
+
+int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	DRM_DEBUG("\n");
+
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	DEV_INIT_TEST_WITH_RETURN(dev->dev_private);
+
+	return r128_do_engine_reset(dev);
+}
+
+int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	return -EINVAL;
+}
+
+/* ================================================================
+ * Freelist management
+ */
+#define R128_BUFFER_USED	0xffffffff
+#define R128_BUFFER_FREE	0
+
+#if 0
+static int r128_freelist_init(struct drm_device *dev)
+{
+	struct drm_device_dma *dma = dev->dma;
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	struct drm_buf *buf;
+	drm_r128_buf_priv_t *buf_priv;
+	drm_r128_freelist_t *entry;
+	int i;
+
+	dev_priv->head = kzalloc(sizeof(drm_r128_freelist_t), GFP_KERNEL);
+	if (dev_priv->head == NULL)
+		return -ENOMEM;
+
+	dev_priv->head->age = R128_BUFFER_USED;
+
+	for (i = 0; i < dma->buf_count; i++) {
+		buf = dma->buflist[i];
+		buf_priv = buf->dev_private;
+
+		entry = kmalloc(sizeof(drm_r128_freelist_t), GFP_KERNEL);
+		if (!entry)
+			return -ENOMEM;
+
+		entry->age = R128_BUFFER_FREE;
+		entry->buf = buf;
+		entry->prev = dev_priv->head;
+		entry->next = dev_priv->head->next;
+		if (!entry->next)
+			dev_priv->tail = entry;
+
+		buf_priv->discard = 0;
+		buf_priv->dispatched = 0;
+		buf_priv->list_entry = entry;
+
+		dev_priv->head->next = entry;
+
+		if (dev_priv->head->next)
+			dev_priv->head->next->prev = entry;
+	}
+
+	return 0;
+
+}
+#endif
+
+static struct drm_buf *r128_freelist_get(struct drm_device * dev)
+{
+	struct drm_device_dma *dma = dev->dma;
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_r128_buf_priv_t *buf_priv;
+	struct drm_buf *buf;
+	int i, t;
+
+	/* FIXME: Optimize -- use freelist code */
+
+	for (i = 0; i < dma->buf_count; i++) {
+		buf = dma->buflist[i];
+		buf_priv = buf->dev_private;
+		if (!buf->file_priv)
+			return buf;
+	}
+
+	for (t = 0; t < dev_priv->usec_timeout; t++) {
+		u32 done_age = R128_READ(R128_LAST_DISPATCH_REG);
+
+		for (i = 0; i < dma->buf_count; i++) {
+			buf = dma->buflist[i];
+			buf_priv = buf->dev_private;
+			if (buf->pending && buf_priv->age <= done_age) {
+				/* The buffer has been processed, so it
+				 * can now be used.
+				 */
+				buf->pending = 0;
+				return buf;
+			}
+		}
+		udelay(1);
+	}
+
+	DRM_DEBUG("returning NULL!\n");
+	return NULL;
+}
+
+void r128_freelist_reset(struct drm_device *dev)
+{
+	struct drm_device_dma *dma = dev->dma;
+	int i;
+
+	for (i = 0; i < dma->buf_count; i++) {
+		struct drm_buf *buf = dma->buflist[i];
+		drm_r128_buf_priv_t *buf_priv = buf->dev_private;
+		buf_priv->age = 0;
+	}
+}
+
+/* ================================================================
+ * CCE command submission
+ */
+
+int r128_wait_ring(drm_r128_private_t *dev_priv, int n)
+{
+	drm_r128_ring_buffer_t *ring = &dev_priv->ring;
+	int i;
+
+	for (i = 0; i < dev_priv->usec_timeout; i++) {
+		r128_update_ring_snapshot(dev_priv);
+		if (ring->space >= n)
+			return 0;
+		udelay(1);
+	}
+
+	/* FIXME: This is being ignored... */
+	DRM_ERROR("failed!\n");
+	return -EBUSY;
+}
+
+static int r128_cce_get_buffers(struct drm_device *dev,
+				struct drm_file *file_priv,
+				struct drm_dma *d)
+{
+	int i;
+	struct drm_buf *buf;
+
+	for (i = d->granted_count; i < d->request_count; i++) {
+		buf = r128_freelist_get(dev);
+		if (!buf)
+			return -EAGAIN;
+
+		buf->file_priv = file_priv;
+
+		if (copy_to_user(&d->request_indices[i], &buf->idx,
+				     sizeof(buf->idx)))
+			return -EFAULT;
+		if (copy_to_user(&d->request_sizes[i], &buf->total,
+				     sizeof(buf->total)))
+			return -EFAULT;
+
+		d->granted_count++;
+	}
+	return 0;
+}
+
+int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_device_dma *dma = dev->dma;
+	int ret = 0;
+	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",
+			  task_pid_nr(current), d->send_count);
+		return -EINVAL;
+	}
+
+	/* We'll send you buffers.
+	 */
+	if (d->request_count < 0 || d->request_count > dma->buf_count) {
+		DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
+			  task_pid_nr(current), d->request_count, dma->buf_count);
+		return -EINVAL;
+	}
+
+	d->granted_count = 0;
+
+	if (d->request_count)
+		ret = r128_cce_get_buffers(dev, file_priv, d);
+
+	return ret;
+}
diff --git a/marvell/linux/drivers/gpu/drm/r128/r128_drv.c b/marvell/linux/drivers/gpu/drm/r128/r128_drv.c
new file mode 100644
index 0000000..fd74f74
--- /dev/null
+++ b/marvell/linux/drivers/gpu/drm/r128/r128_drv.c
@@ -0,0 +1,114 @@
+/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*-
+ * Created: Mon Dec 13 09:47:27 1999 by faith@precisioninsight.com
+ *
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * 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
+ * VA LINUX SYSTEMS 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:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *    Gareth Hughes <gareth@valinux.com>
+ */
+
+#include <linux/module.h>
+
+#include <drm/drm_drv.h>
+#include <drm/drm_file.h>
+#include <drm/drm_pci.h>
+#include <drm/drm_pciids.h>
+#include <drm/drm_vblank.h>
+#include <drm/r128_drm.h>
+
+#include "r128_drv.h"
+
+static struct pci_device_id pciidlist[] = {
+	r128_PCI_IDS
+};
+
+static const struct file_operations r128_driver_fops = {
+	.owner = THIS_MODULE,
+	.open = drm_open,
+	.release = drm_release,
+	.unlocked_ioctl = drm_ioctl,
+	.mmap = drm_legacy_mmap,
+	.poll = drm_poll,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = r128_compat_ioctl,
+#endif
+	.llseek = noop_llseek,
+};
+
+static struct drm_driver driver = {
+	.driver_features =
+	    DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG | DRIVER_LEGACY |
+	    DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ,
+	.dev_priv_size = sizeof(drm_r128_buf_priv_t),
+	.load = r128_driver_load,
+	.preclose = r128_driver_preclose,
+	.lastclose = r128_driver_lastclose,
+	.get_vblank_counter = r128_get_vblank_counter,
+	.enable_vblank = r128_enable_vblank,
+	.disable_vblank = r128_disable_vblank,
+	.irq_preinstall = r128_driver_irq_preinstall,
+	.irq_postinstall = r128_driver_irq_postinstall,
+	.irq_uninstall = r128_driver_irq_uninstall,
+	.irq_handler = r128_driver_irq_handler,
+	.ioctls = r128_ioctls,
+	.dma_ioctl = r128_cce_buffers,
+	.fops = &r128_driver_fops,
+	.name = DRIVER_NAME,
+	.desc = DRIVER_DESC,
+	.date = DRIVER_DATE,
+	.major = DRIVER_MAJOR,
+	.minor = DRIVER_MINOR,
+	.patchlevel = DRIVER_PATCHLEVEL,
+};
+
+int r128_driver_load(struct drm_device *dev, unsigned long flags)
+{
+	pci_set_master(dev->pdev);
+	return drm_vblank_init(dev, 1);
+}
+
+static struct pci_driver r128_pci_driver = {
+	.name = DRIVER_NAME,
+	.id_table = pciidlist,
+};
+
+static int __init r128_init(void)
+{
+	driver.num_ioctls = r128_max_ioctl;
+
+	return drm_legacy_pci_init(&driver, &r128_pci_driver);
+}
+
+static void __exit r128_exit(void)
+{
+	drm_legacy_pci_exit(&driver, &r128_pci_driver);
+}
+
+module_init(r128_init);
+module_exit(r128_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL and additional rights");
diff --git a/marvell/linux/drivers/gpu/drm/r128/r128_drv.h b/marvell/linux/drivers/gpu/drm/r128/r128_drv.h
new file mode 100644
index 0000000..ba8c30e
--- /dev/null
+++ b/marvell/linux/drivers/gpu/drm/r128/r128_drv.h
@@ -0,0 +1,543 @@
+/* r128_drv.h -- Private header for r128 driver -*- linux-c -*-
+ * Created: Mon Dec 13 09:51:11 1999 by faith@precisioninsight.com
+ */
+/*
+ * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * 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:
+ *    Rickard E. (Rik) Faith <faith@valinux.com>
+ *    Kevin E. Martin <martin@valinux.com>
+ *    Gareth Hughes <gareth@valinux.com>
+ *    Michel D�zer <daenzerm@student.ethz.ch>
+ */
+
+#ifndef __R128_DRV_H__
+#define __R128_DRV_H__
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/irqreturn.h>
+
+#include <drm/ati_pcigart.h>
+#include <drm/drm_ioctl.h>
+#include <drm/drm_legacy.h>
+#include <drm/r128_drm.h>
+
+/* General customization:
+ */
+#define DRIVER_AUTHOR		"Gareth Hughes, VA Linux Systems Inc."
+
+#define DRIVER_NAME		"r128"
+#define DRIVER_DESC		"ATI Rage 128"
+#define DRIVER_DATE		"20030725"
+
+/* Interface history:
+ *
+ * ??  - ??
+ * 2.4 - Add support for ycbcr textures (no new ioctls)
+ * 2.5 - Add FLIP ioctl, disable FULLSCREEN.
+ */
+#define DRIVER_MAJOR		2
+#define DRIVER_MINOR		5
+#define DRIVER_PATCHLEVEL	0
+
+#define GET_RING_HEAD(dev_priv)		R128_READ(R128_PM4_BUFFER_DL_RPTR)
+
+typedef struct drm_r128_freelist {
+	unsigned int age;
+	struct drm_buf *buf;
+	struct drm_r128_freelist *next;
+	struct drm_r128_freelist *prev;
+} drm_r128_freelist_t;
+
+typedef struct drm_r128_ring_buffer {
+	u32 *start;
+	u32 *end;
+	int size;
+	int size_l2qw;
+
+	u32 tail;
+	u32 tail_mask;
+	int space;
+
+	int high_mark;
+} drm_r128_ring_buffer_t;
+
+typedef struct drm_r128_private {
+	drm_r128_ring_buffer_t ring;
+	drm_r128_sarea_t *sarea_priv;
+
+	int cce_mode;
+	int cce_fifo_size;
+	int cce_running;
+
+	drm_r128_freelist_t *head;
+	drm_r128_freelist_t *tail;
+
+	int usec_timeout;
+	int is_pci;
+	unsigned long cce_buffers_offset;
+
+	atomic_t idle_count;
+
+	int page_flipping;
+	int current_page;
+	u32 crtc_offset;
+	u32 crtc_offset_cntl;
+
+	atomic_t vbl_received;
+
+	u32 color_fmt;
+	unsigned int front_offset;
+	unsigned int front_pitch;
+	unsigned int back_offset;
+	unsigned int back_pitch;
+
+	u32 depth_fmt;
+	unsigned int depth_offset;
+	unsigned int depth_pitch;
+	unsigned int span_offset;
+
+	u32 front_pitch_offset_c;
+	u32 back_pitch_offset_c;
+	u32 depth_pitch_offset_c;
+	u32 span_pitch_offset_c;
+
+	drm_local_map_t *sarea;
+	drm_local_map_t *mmio;
+	drm_local_map_t *cce_ring;
+	drm_local_map_t *ring_rptr;
+	drm_local_map_t *agp_textures;
+	struct drm_ati_pcigart_info gart_info;
+} drm_r128_private_t;
+
+typedef struct drm_r128_buf_priv {
+	u32 age;
+	int prim;
+	int discard;
+	int dispatched;
+	drm_r128_freelist_t *list_entry;
+} drm_r128_buf_priv_t;
+
+extern const struct drm_ioctl_desc r128_ioctls[];
+extern int r128_max_ioctl;
+
+				/* r128_cce.c */
+extern int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
+
+extern int r128_cce_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_cce_depth(struct drm_device *dev, void *data, struct drm_file *file_priv);
+extern int r128_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv);
+
+extern void r128_freelist_reset(struct drm_device *dev);
+
+extern int r128_wait_ring(drm_r128_private_t *dev_priv, int n);
+
+extern int r128_do_cce_idle(drm_r128_private_t *dev_priv);
+extern int r128_do_cleanup_cce(struct drm_device *dev);
+
+extern int r128_enable_vblank(struct drm_device *dev, unsigned int pipe);
+extern void r128_disable_vblank(struct drm_device *dev, unsigned int pipe);
+extern u32 r128_get_vblank_counter(struct drm_device *dev, unsigned int pipe);
+extern irqreturn_t r128_driver_irq_handler(int irq, void *arg);
+extern void r128_driver_irq_preinstall(struct drm_device *dev);
+extern int r128_driver_irq_postinstall(struct drm_device *dev);
+extern void r128_driver_irq_uninstall(struct drm_device *dev);
+extern void r128_driver_lastclose(struct drm_device *dev);
+extern int r128_driver_load(struct drm_device *dev, unsigned long flags);
+extern void r128_driver_preclose(struct drm_device *dev,
+				 struct drm_file *file_priv);
+
+extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
+			      unsigned long arg);
+
+/* Register definitions, register access macros and drmAddMap constants
+ * for Rage 128 kernel driver.
+ */
+
+#define R128_AUX_SC_CNTL		0x1660
+#	define R128_AUX1_SC_EN			(1 << 0)
+#	define R128_AUX1_SC_MODE_OR		(0 << 1)
+#	define R128_AUX1_SC_MODE_NAND		(1 << 1)
+#	define R128_AUX2_SC_EN			(1 << 2)
+#	define R128_AUX2_SC_MODE_OR		(0 << 3)
+#	define R128_AUX2_SC_MODE_NAND		(1 << 3)
+#	define R128_AUX3_SC_EN			(1 << 4)
+#	define R128_AUX3_SC_MODE_OR		(0 << 5)
+#	define R128_AUX3_SC_MODE_NAND		(1 << 5)
+#define R128_AUX1_SC_LEFT		0x1664
+#define R128_AUX1_SC_RIGHT		0x1668
+#define R128_AUX1_SC_TOP		0x166c
+#define R128_AUX1_SC_BOTTOM		0x1670
+#define R128_AUX2_SC_LEFT		0x1674
+#define R128_AUX2_SC_RIGHT		0x1678
+#define R128_AUX2_SC_TOP		0x167c
+#define R128_AUX2_SC_BOTTOM		0x1680
+#define R128_AUX3_SC_LEFT		0x1684
+#define R128_AUX3_SC_RIGHT		0x1688
+#define R128_AUX3_SC_TOP		0x168c
+#define R128_AUX3_SC_BOTTOM		0x1690
+
+#define R128_BRUSH_DATA0		0x1480
+#define R128_BUS_CNTL			0x0030
+#	define R128_BUS_MASTER_DIS		(1 << 6)
+
+#define R128_CLOCK_CNTL_INDEX		0x0008
+#define R128_CLOCK_CNTL_DATA		0x000c
+#	define R128_PLL_WR_EN			(1 << 7)
+#define R128_CONSTANT_COLOR_C		0x1d34
+#define R128_CRTC_OFFSET		0x0224
+#define R128_CRTC_OFFSET_CNTL		0x0228
+#	define R128_CRTC_OFFSET_FLIP_CNTL	(1 << 16)
+
+#define R128_DP_GUI_MASTER_CNTL		0x146c
+#       define R128_GMC_SRC_PITCH_OFFSET_CNTL	(1    <<  0)
+#       define R128_GMC_DST_PITCH_OFFSET_CNTL	(1    <<  1)
+#	define R128_GMC_BRUSH_SOLID_COLOR	(13   <<  4)
+#	define R128_GMC_BRUSH_NONE		(15   <<  4)
+#	define R128_GMC_DST_16BPP		(4    <<  8)
+#	define R128_GMC_DST_24BPP		(5    <<  8)
+#	define R128_GMC_DST_32BPP		(6    <<  8)
+#       define R128_GMC_DST_DATATYPE_SHIFT	8
+#	define R128_GMC_SRC_DATATYPE_COLOR	(3    << 12)
+#	define R128_DP_SRC_SOURCE_MEMORY	(2    << 24)
+#	define R128_DP_SRC_SOURCE_HOST_DATA	(3    << 24)
+#	define R128_GMC_CLR_CMP_CNTL_DIS	(1    << 28)
+#	define R128_GMC_AUX_CLIP_DIS		(1    << 29)
+#	define R128_GMC_WR_MSK_DIS		(1    << 30)
+#	define R128_ROP3_S			0x00cc0000
+#	define R128_ROP3_P			0x00f00000
+#define R128_DP_WRITE_MASK		0x16cc
+#define R128_DST_PITCH_OFFSET_C		0x1c80
+#	define R128_DST_TILE			(1 << 31)
+
+#define R128_GEN_INT_CNTL		0x0040
+#	define R128_CRTC_VBLANK_INT_EN		(1 <<  0)
+#define R128_GEN_INT_STATUS		0x0044
+#	define R128_CRTC_VBLANK_INT		(1 <<  0)
+#	define R128_CRTC_VBLANK_INT_AK		(1 <<  0)
+#define R128_GEN_RESET_CNTL		0x00f0
+#	define R128_SOFT_RESET_GUI		(1 <<  0)
+
+#define R128_GUI_SCRATCH_REG0		0x15e0
+#define R128_GUI_SCRATCH_REG1		0x15e4
+#define R128_GUI_SCRATCH_REG2		0x15e8
+#define R128_GUI_SCRATCH_REG3		0x15ec
+#define R128_GUI_SCRATCH_REG4		0x15f0
+#define R128_GUI_SCRATCH_REG5		0x15f4
+
+#define R128_GUI_STAT			0x1740
+#	define R128_GUI_FIFOCNT_MASK		0x0fff
+#	define R128_GUI_ACTIVE			(1 << 31)
+
+#define R128_MCLK_CNTL			0x000f
+#	define R128_FORCE_GCP			(1 << 16)
+#	define R128_FORCE_PIPE3D_CP		(1 << 17)
+#	define R128_FORCE_RCP			(1 << 18)
+
+#define R128_PC_GUI_CTLSTAT		0x1748
+#define R128_PC_NGUI_CTLSTAT		0x0184
+#	define R128_PC_FLUSH_GUI		(3 << 0)
+#	define R128_PC_RI_GUI			(1 << 2)
+#	define R128_PC_FLUSH_ALL		0x00ff
+#	define R128_PC_BUSY			(1 << 31)
+
+#define R128_PCI_GART_PAGE		0x017c
+#define R128_PRIM_TEX_CNTL_C		0x1cb0
+
+#define R128_SCALE_3D_CNTL		0x1a00
+#define R128_SEC_TEX_CNTL_C		0x1d00
+#define R128_SEC_TEXTURE_BORDER_COLOR_C	0x1d3c
+#define R128_SETUP_CNTL			0x1bc4
+#define R128_STEN_REF_MASK_C		0x1d40
+
+#define R128_TEX_CNTL_C			0x1c9c
+#	define R128_TEX_CACHE_FLUSH		(1 << 23)
+
+#define R128_WAIT_UNTIL			0x1720
+#	define R128_EVENT_CRTC_OFFSET		(1 << 0)
+#define R128_WINDOW_XY_OFFSET		0x1bcc
+
+/* CCE registers
+ */
+#define R128_PM4_BUFFER_OFFSET		0x0700
+#define R128_PM4_BUFFER_CNTL		0x0704
+#	define R128_PM4_MASK			(15 << 28)
+#	define R128_PM4_NONPM4			(0  << 28)
+#	define R128_PM4_192PIO			(1  << 28)
+#	define R128_PM4_192BM			(2  << 28)
+#	define R128_PM4_128PIO_64INDBM		(3  << 28)
+#	define R128_PM4_128BM_64INDBM		(4  << 28)
+#	define R128_PM4_64PIO_128INDBM		(5  << 28)
+#	define R128_PM4_64BM_128INDBM		(6  << 28)
+#	define R128_PM4_64PIO_64VCBM_64INDBM	(7  << 28)
+#	define R128_PM4_64BM_64VCBM_64INDBM	(8  << 28)
+#	define R128_PM4_64PIO_64VCPIO_64INDPIO	(15 << 28)
+#	define R128_PM4_BUFFER_CNTL_NOUPDATE	(1  << 27)
+
+#define R128_PM4_BUFFER_WM_CNTL		0x0708
+#	define R128_WMA_SHIFT			0
+#	define R128_WMB_SHIFT			8
+#	define R128_WMC_SHIFT			16
+#	define R128_WB_WM_SHIFT			24
+
+#define R128_PM4_BUFFER_DL_RPTR_ADDR	0x070c
+#define R128_PM4_BUFFER_DL_RPTR		0x0710
+#define R128_PM4_BUFFER_DL_WPTR		0x0714
+#	define R128_PM4_BUFFER_DL_DONE		(1 << 31)
+
+#define R128_PM4_VC_FPU_SETUP		0x071c
+
+#define R128_PM4_IW_INDOFF		0x0738
+#define R128_PM4_IW_INDSIZE		0x073c
+
+#define R128_PM4_STAT			0x07b8
+#	define R128_PM4_FIFOCNT_MASK		0x0fff
+#	define R128_PM4_BUSY			(1 << 16)
+#	define R128_PM4_GUI_ACTIVE		(1 << 31)
+
+#define R128_PM4_MICROCODE_ADDR		0x07d4
+#define R128_PM4_MICROCODE_RADDR	0x07d8
+#define R128_PM4_MICROCODE_DATAH	0x07dc
+#define R128_PM4_MICROCODE_DATAL	0x07e0
+
+#define R128_PM4_BUFFER_ADDR		0x07f0
+#define R128_PM4_MICRO_CNTL		0x07fc
+#	define R128_PM4_MICRO_FREERUN		(1 << 30)
+
+#define R128_PM4_FIFO_DATA_EVEN		0x1000
+#define R128_PM4_FIFO_DATA_ODD		0x1004
+
+/* CCE command packets
+ */
+#define R128_CCE_PACKET0		0x00000000
+#define R128_CCE_PACKET1		0x40000000
+#define R128_CCE_PACKET2		0x80000000
+#define R128_CCE_PACKET3		0xC0000000
+#	define R128_CNTL_HOSTDATA_BLT		0x00009400
+#	define R128_CNTL_PAINT_MULTI		0x00009A00
+#	define R128_CNTL_BITBLT_MULTI		0x00009B00
+#	define R128_3D_RNDR_GEN_INDX_PRIM	0x00002300
+
+#define R128_CCE_PACKET_MASK		0xC0000000
+#define R128_CCE_PACKET_COUNT_MASK	0x3fff0000
+#define R128_CCE_PACKET0_REG_MASK	0x000007ff
+#define R128_CCE_PACKET1_REG0_MASK	0x000007ff
+#define R128_CCE_PACKET1_REG1_MASK	0x003ff800
+
+#define R128_CCE_VC_CNTL_PRIM_TYPE_NONE		0x00000000
+#define R128_CCE_VC_CNTL_PRIM_TYPE_POINT	0x00000001
+#define R128_CCE_VC_CNTL_PRIM_TYPE_LINE		0x00000002
+#define R128_CCE_VC_CNTL_PRIM_TYPE_POLY_LINE	0x00000003
+#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST	0x00000004
+#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_FAN	0x00000005
+#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_STRIP	0x00000006
+#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2	0x00000007
+#define R128_CCE_VC_CNTL_PRIM_WALK_IND		0x00000010
+#define R128_CCE_VC_CNTL_PRIM_WALK_LIST		0x00000020
+#define R128_CCE_VC_CNTL_PRIM_WALK_RING		0x00000030
+#define R128_CCE_VC_CNTL_NUM_SHIFT		16
+
+#define R128_DATATYPE_VQ		0
+#define R128_DATATYPE_CI4		1
+#define R128_DATATYPE_CI8		2
+#define R128_DATATYPE_ARGB1555		3
+#define R128_DATATYPE_RGB565		4
+#define R128_DATATYPE_RGB888		5
+#define R128_DATATYPE_ARGB8888		6
+#define R128_DATATYPE_RGB332		7
+#define R128_DATATYPE_Y8		8
+#define R128_DATATYPE_RGB8		9
+#define R128_DATATYPE_CI16		10
+#define R128_DATATYPE_YVYU422		11
+#define R128_DATATYPE_VYUY422		12
+#define R128_DATATYPE_AYUV444		14
+#define R128_DATATYPE_ARGB4444		15
+
+/* Constants */
+#define R128_AGP_OFFSET			0x02000000
+
+#define R128_WATERMARK_L		16
+#define R128_WATERMARK_M		8
+#define R128_WATERMARK_N		8
+#define R128_WATERMARK_K		128
+
+#define R128_MAX_USEC_TIMEOUT		100000	/* 100 ms */
+
+#define R128_LAST_FRAME_REG		R128_GUI_SCRATCH_REG0
+#define R128_LAST_DISPATCH_REG		R128_GUI_SCRATCH_REG1
+#define R128_MAX_VB_AGE			0x7fffffff
+#define R128_MAX_VB_VERTS		(0xffff)
+
+#define R128_RING_HIGH_MARK		128
+
+#define R128_PERFORMANCE_BOXES		0
+
+#define R128_PCIGART_TABLE_SIZE         32768
+
+#define R128_READ(reg)		readl(((void __iomem *)dev_priv->mmio->handle) + (reg))
+#define R128_WRITE(reg, val)	writel(val, ((void __iomem *)dev_priv->mmio->handle) + (reg))
+#define R128_READ8(reg)		readb(((void __iomem *)dev_priv->mmio->handle) + (reg))
+#define R128_WRITE8(reg, val)	writeb(val, ((void __iomem *)dev_priv->mmio->handle) + (reg))
+
+#define R128_WRITE_PLL(addr, val)					\
+do {									\
+	R128_WRITE8(R128_CLOCK_CNTL_INDEX,				\
+		    ((addr) & 0x1f) | R128_PLL_WR_EN);			\
+	R128_WRITE(R128_CLOCK_CNTL_DATA, (val));			\
+} while (0)
+
+#define CCE_PACKET0(reg, n)		(R128_CCE_PACKET0 |		\
+					 ((n) << 16) | ((reg) >> 2))
+#define CCE_PACKET1(reg0, reg1)		(R128_CCE_PACKET1 |		\
+					 (((reg1) >> 2) << 11) | ((reg0) >> 2))
+#define CCE_PACKET2()			(R128_CCE_PACKET2)
+#define CCE_PACKET3(pkt, n)		(R128_CCE_PACKET3 |		\
+					 (pkt) | ((n) << 16))
+
+static __inline__ void r128_update_ring_snapshot(drm_r128_private_t *dev_priv)
+{
+	drm_r128_ring_buffer_t *ring = &dev_priv->ring;
+	ring->space = (GET_RING_HEAD(dev_priv) - ring->tail) * sizeof(u32);
+	if (ring->space <= 0)
+		ring->space += ring->size;
+}
+
+/* ================================================================
+ * Misc helper macros
+ */
+
+#define DEV_INIT_TEST_WITH_RETURN(_dev_priv)				\
+do {									\
+	if (!_dev_priv) {						\
+		DRM_ERROR("called with no initialization\n");		\
+		return -EINVAL;						\
+	}								\
+} while (0)
+
+#define RING_SPACE_TEST_WITH_RETURN(dev_priv)				\
+do {									\
+	drm_r128_ring_buffer_t *ring = &dev_priv->ring; int i;		\
+	if (ring->space < ring->high_mark) {				\
+		for (i = 0 ; i < dev_priv->usec_timeout ; i++) {	\
+			r128_update_ring_snapshot(dev_priv);		\
+			if (ring->space >= ring->high_mark)		\
+				goto __ring_space_done;			\
+			udelay(1);					\
+		}							\
+		DRM_ERROR("ring space check failed!\n");		\
+		return -EBUSY;						\
+	}								\
+ __ring_space_done:							\
+	;								\
+} while (0)
+
+#define VB_AGE_TEST_WITH_RETURN(dev_priv)				\
+do {									\
+	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;		\
+	if (sarea_priv->last_dispatch >= R128_MAX_VB_AGE) {		\
+		int __ret = r128_do_cce_idle(dev_priv);			\
+		if (__ret)						\
+			return __ret;					\
+		sarea_priv->last_dispatch = 0;				\
+		r128_freelist_reset(dev);				\
+	}								\
+} while (0)
+
+#define R128_WAIT_UNTIL_PAGE_FLIPPED() do {				\
+	OUT_RING(CCE_PACKET0(R128_WAIT_UNTIL, 0));			\
+	OUT_RING(R128_EVENT_CRTC_OFFSET);				\
+} while (0)
+
+/* ================================================================
+ * Ring control
+ */
+
+#define R128_VERBOSE	0
+
+#define RING_LOCALS							\
+	int write, _nr; unsigned int tail_mask; volatile u32 *ring;
+
+#define BEGIN_RING(n) do {						\
+	if (R128_VERBOSE)						\
+		DRM_INFO("BEGIN_RING(%d)\n", (n));			\
+	if (dev_priv->ring.space <= (n) * sizeof(u32)) {		\
+		COMMIT_RING();						\
+		r128_wait_ring(dev_priv, (n) * sizeof(u32));		\
+	}								\
+	_nr = n; dev_priv->ring.space -= (n) * sizeof(u32);		\
+	ring = dev_priv->ring.start;					\
+	write = dev_priv->ring.tail;					\
+	tail_mask = dev_priv->ring.tail_mask;				\
+} while (0)
+
+/* You can set this to zero if you want.  If the card locks up, you'll
+ * need to keep this set.  It works around a bug in early revs of the
+ * Rage 128 chipset, where the CCE would read 32 dwords past the end of
+ * the ring buffer before wrapping around.
+ */
+#define R128_BROKEN_CCE	1
+
+#define ADVANCE_RING() do {						\
+	if (R128_VERBOSE)						\
+		DRM_INFO("ADVANCE_RING() wr=0x%06x tail=0x%06x\n",	\
+			 write, dev_priv->ring.tail);			\
+	if (R128_BROKEN_CCE && write < 32)				\
+		memcpy(dev_priv->ring.end,				\
+		       dev_priv->ring.start,				\
+		       write * sizeof(u32));				\
+	if (((dev_priv->ring.tail + _nr) & tail_mask) != write)		\
+		DRM_ERROR(						\
+			"ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n",	\
+			((dev_priv->ring.tail + _nr) & tail_mask),	\
+			write, __LINE__);				\
+	else								\
+		dev_priv->ring.tail = write;				\
+} while (0)
+
+#define COMMIT_RING() do {						\
+	if (R128_VERBOSE)						\
+		DRM_INFO("COMMIT_RING() tail=0x%06x\n",			\
+			 dev_priv->ring.tail);				\
+	mb();						\
+	R128_WRITE(R128_PM4_BUFFER_DL_WPTR, dev_priv->ring.tail);	\
+	R128_READ(R128_PM4_BUFFER_DL_WPTR);				\
+} while (0)
+
+#define OUT_RING(x) do {						\
+	if (R128_VERBOSE)						\
+		DRM_INFO("   OUT_RING( 0x%08x ) at 0x%x\n",		\
+			 (unsigned int)(x), write);			\
+	ring[write++] = cpu_to_le32(x);					\
+	write &= tail_mask;						\
+} while (0)
+
+#endif				/* __R128_DRV_H__ */
diff --git a/marvell/linux/drivers/gpu/drm/r128/r128_ioc32.c b/marvell/linux/drivers/gpu/drm/r128/r128_ioc32.c
new file mode 100644
index 0000000..6ac7175
--- /dev/null
+++ b/marvell/linux/drivers/gpu/drm/r128/r128_ioc32.c
@@ -0,0 +1,199 @@
+/**
+ * \file r128_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the R128 DRM.
+ *
+ * \author Dave Airlie <airlied@linux.ie> with code from patches by Egbert Eich
+ *
+ * Copyright (C) Paul Mackerras 2005
+ * Copyright (C) Egbert Eich 2003,2004
+ * Copyright (C) Dave Airlie 2005
+ * 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
+ * THE AUTHOR 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/compat.h>
+
+#include <drm/r128_drm.h>
+
+#include "r128_drv.h"
+
+typedef struct drm_r128_init32 {
+	int func;
+	unsigned int sarea_priv_offset;
+	int is_pci;
+	int cce_mode;
+	int cce_secure;
+	int ring_size;
+	int usec_timeout;
+
+	unsigned int fb_bpp;
+	unsigned int front_offset, front_pitch;
+	unsigned int back_offset, back_pitch;
+	unsigned int depth_bpp;
+	unsigned int depth_offset, depth_pitch;
+	unsigned int span_offset;
+
+	unsigned int fb_offset;
+	unsigned int mmio_offset;
+	unsigned int ring_offset;
+	unsigned int ring_rptr_offset;
+	unsigned int buffers_offset;
+	unsigned int agp_textures_offset;
+} drm_r128_init32_t;
+
+static int compat_r128_init(struct file *file, unsigned int cmd,
+			    unsigned long arg)
+{
+	drm_r128_init32_t init32;
+	drm_r128_init_t init;
+
+	if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
+		return -EFAULT;
+
+	init.func = init32.func;
+	init.sarea_priv_offset = init32.sarea_priv_offset;
+	init.is_pci = init32.is_pci;
+	init.cce_mode = init32.cce_mode;
+	init.cce_secure = init32.cce_secure;
+	init.ring_size = init32.ring_size;
+	init.usec_timeout = init32.usec_timeout;
+	init.fb_bpp = init32.fb_bpp;
+	init.front_offset = init32.front_offset;
+	init.front_pitch = init32.front_pitch;
+	init.back_offset = init32.back_offset;
+	init.back_pitch = init32.back_pitch;
+	init.depth_bpp = init32.depth_bpp;
+	init.depth_offset = init32.depth_offset;
+	init.depth_pitch = init32.depth_pitch;
+	init.span_offset = init32.span_offset;
+	init.fb_offset = init32.fb_offset;
+	init.mmio_offset = init32.mmio_offset;
+	init.ring_offset = init32.ring_offset;
+	init.ring_rptr_offset = init32.ring_rptr_offset;
+	init.buffers_offset = init32.buffers_offset;
+	init.agp_textures_offset = init32.agp_textures_offset;
+
+	return drm_ioctl_kernel(file, r128_cce_init, &init,
+			DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
+}
+
+typedef struct drm_r128_depth32 {
+	int func;
+	int n;
+	u32 x;
+	u32 y;
+	u32 buffer;
+	u32 mask;
+} drm_r128_depth32_t;
+
+static int compat_r128_depth(struct file *file, unsigned int cmd,
+			     unsigned long arg)
+{
+	drm_r128_depth32_t depth32;
+	drm_r128_depth_t depth;
+
+	if (copy_from_user(&depth32, (void __user *)arg, sizeof(depth32)))
+		return -EFAULT;
+
+	depth.func = depth32.func;
+	depth.n = depth32.n;
+	depth.x = compat_ptr(depth32.x);
+	depth.y = compat_ptr(depth32.y);
+	depth.buffer = compat_ptr(depth32.buffer);
+	depth.mask = compat_ptr(depth32.mask);
+
+	return drm_ioctl_kernel(file, r128_cce_depth, &depth, DRM_AUTH);
+}
+
+typedef struct drm_r128_stipple32 {
+	u32 mask;
+} drm_r128_stipple32_t;
+
+static int compat_r128_stipple(struct file *file, unsigned int cmd,
+			       unsigned long arg)
+{
+	drm_r128_stipple32_t stipple32;
+	drm_r128_stipple_t stipple;
+
+	if (copy_from_user(&stipple32, (void __user *)arg, sizeof(stipple32)))
+		return -EFAULT;
+
+	stipple.mask = compat_ptr(stipple32.mask);
+
+	return drm_ioctl_kernel(file, r128_cce_stipple, &stipple, DRM_AUTH);
+}
+
+typedef struct drm_r128_getparam32 {
+	int param;
+	u32 value;
+} drm_r128_getparam32_t;
+
+static int compat_r128_getparam(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	drm_r128_getparam32_t getparam32;
+	drm_r128_getparam_t getparam;
+
+	if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32)))
+		return -EFAULT;
+
+	getparam.param = getparam32.param;
+	getparam.value = compat_ptr(getparam32.value);
+
+	return drm_ioctl_kernel(file, r128_getparam, &getparam, DRM_AUTH);
+}
+
+drm_ioctl_compat_t *r128_compat_ioctls[] = {
+	[DRM_R128_INIT] = compat_r128_init,
+	[DRM_R128_DEPTH] = compat_r128_depth,
+	[DRM_R128_STIPPLE] = compat_r128_stipple,
+	[DRM_R128_GETPARAM] = compat_r128_getparam,
+};
+
+/**
+ * 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 r128_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);
+
+	if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(r128_compat_ioctls))
+		fn = r128_compat_ioctls[nr - DRM_COMMAND_BASE];
+
+	if (fn != NULL)
+		ret = (*fn) (filp, cmd, arg);
+	else
+		ret = drm_ioctl(filp, cmd, arg);
+
+	return ret;
+}
diff --git a/marvell/linux/drivers/gpu/drm/r128/r128_irq.c b/marvell/linux/drivers/gpu/drm/r128/r128_irq.c
new file mode 100644
index 0000000..d84e9c9
--- /dev/null
+++ b/marvell/linux/drivers/gpu/drm/r128/r128_irq.c
@@ -0,0 +1,118 @@
+/* r128_irq.c -- IRQ handling for radeon -*- linux-c -*- */
+/*
+ * Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
+ *
+ * The Weather Channel (TM) funded Tungsten Graphics to develop the
+ * initial release of the Radeon 8500 driver under the XFree86 license.
+ * This notice must be preserved.
+ *
+ * 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:
+ *    Keith Whitwell <keith@tungstengraphics.com>
+ *    Eric Anholt <anholt@FreeBSD.org>
+ */
+
+#include <drm/drm_device.h>
+#include <drm/drm_print.h>
+#include <drm/drm_vblank.h>
+#include <drm/r128_drm.h>
+
+#include "r128_drv.h"
+
+u32 r128_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
+{
+	const drm_r128_private_t *dev_priv = dev->dev_private;
+
+	if (pipe != 0)
+		return 0;
+
+	return atomic_read(&dev_priv->vbl_received);
+}
+
+irqreturn_t r128_driver_irq_handler(int irq, void *arg)
+{
+	struct drm_device *dev = (struct drm_device *) arg;
+	drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
+	int status;
+
+	status = R128_READ(R128_GEN_INT_STATUS);
+
+	/* VBLANK interrupt */
+	if (status & R128_CRTC_VBLANK_INT) {
+		R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
+		atomic_inc(&dev_priv->vbl_received);
+		drm_handle_vblank(dev, 0);
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+}
+
+int r128_enable_vblank(struct drm_device *dev, unsigned int pipe)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+
+	if (pipe != 0) {
+		DRM_ERROR("%s:  bad crtc %u\n", __func__, pipe);
+		return -EINVAL;
+	}
+
+	R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
+	return 0;
+}
+
+void r128_disable_vblank(struct drm_device *dev, unsigned int pipe)
+{
+	if (pipe != 0)
+		DRM_ERROR("%s:  bad crtc %u\n", __func__, pipe);
+
+	/*
+	 * FIXME: implement proper interrupt disable by using the vblank
+	 * counter register (if available)
+	 *
+	 * R128_WRITE(R128_GEN_INT_CNTL,
+	 *            R128_READ(R128_GEN_INT_CNTL) & ~R128_CRTC_VBLANK_INT_EN);
+	 */
+}
+
+void r128_driver_irq_preinstall(struct drm_device *dev)
+{
+	drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
+
+	/* Disable *all* interrupts */
+	R128_WRITE(R128_GEN_INT_CNTL, 0);
+	/* Clear vblank bit if it's already high */
+	R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
+}
+
+int r128_driver_irq_postinstall(struct drm_device *dev)
+{
+	return 0;
+}
+
+void r128_driver_irq_uninstall(struct drm_device *dev)
+{
+	drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
+	if (!dev_priv)
+		return;
+
+	/* Disable *all* interrupts */
+	R128_WRITE(R128_GEN_INT_CNTL, 0);
+}
diff --git a/marvell/linux/drivers/gpu/drm/r128/r128_state.c b/marvell/linux/drivers/gpu/drm/r128/r128_state.c
new file mode 100644
index 0000000..9d74c9d
--- /dev/null
+++ b/marvell/linux/drivers/gpu/drm/r128/r128_state.c
@@ -0,0 +1,1640 @@
+/* r128_state.c -- State support for r128 -*- linux-c -*-
+ * Created: Thu Jan 27 02:53:43 2000 by gareth@valinux.com
+ */
+/*
+ * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * 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:
+ *    Gareth Hughes <gareth@valinux.com>
+ */
+
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+#include <drm/drm_device.h>
+#include <drm/drm_file.h>
+#include <drm/drm_print.h>
+#include <drm/r128_drm.h>
+
+#include "r128_drv.h"
+
+/* ================================================================
+ * CCE hardware state programming functions
+ */
+
+static void r128_emit_clip_rects(drm_r128_private_t *dev_priv,
+				 struct drm_clip_rect *boxes, int count)
+{
+	u32 aux_sc_cntl = 0x00000000;
+	RING_LOCALS;
+	DRM_DEBUG("\n");
+
+	BEGIN_RING((count < 3 ? count : 3) * 5 + 2);
+
+	if (count >= 1) {
+		OUT_RING(CCE_PACKET0(R128_AUX1_SC_LEFT, 3));
+		OUT_RING(boxes[0].x1);
+		OUT_RING(boxes[0].x2 - 1);
+		OUT_RING(boxes[0].y1);
+		OUT_RING(boxes[0].y2 - 1);
+
+		aux_sc_cntl |= (R128_AUX1_SC_EN | R128_AUX1_SC_MODE_OR);
+	}
+	if (count >= 2) {
+		OUT_RING(CCE_PACKET0(R128_AUX2_SC_LEFT, 3));
+		OUT_RING(boxes[1].x1);
+		OUT_RING(boxes[1].x2 - 1);
+		OUT_RING(boxes[1].y1);
+		OUT_RING(boxes[1].y2 - 1);
+
+		aux_sc_cntl |= (R128_AUX2_SC_EN | R128_AUX2_SC_MODE_OR);
+	}
+	if (count >= 3) {
+		OUT_RING(CCE_PACKET0(R128_AUX3_SC_LEFT, 3));
+		OUT_RING(boxes[2].x1);
+		OUT_RING(boxes[2].x2 - 1);
+		OUT_RING(boxes[2].y1);
+		OUT_RING(boxes[2].y2 - 1);
+
+		aux_sc_cntl |= (R128_AUX3_SC_EN | R128_AUX3_SC_MODE_OR);
+	}
+
+	OUT_RING(CCE_PACKET0(R128_AUX_SC_CNTL, 0));
+	OUT_RING(aux_sc_cntl);
+
+	ADVANCE_RING();
+}
+
+static __inline__ void r128_emit_core(drm_r128_private_t *dev_priv)
+{
+	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
+	RING_LOCALS;
+	DRM_DEBUG("\n");
+
+	BEGIN_RING(2);
+
+	OUT_RING(CCE_PACKET0(R128_SCALE_3D_CNTL, 0));
+	OUT_RING(ctx->scale_3d_cntl);
+
+	ADVANCE_RING();
+}
+
+static __inline__ void r128_emit_context(drm_r128_private_t *dev_priv)
+{
+	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
+	RING_LOCALS;
+	DRM_DEBUG("\n");
+
+	BEGIN_RING(13);
+
+	OUT_RING(CCE_PACKET0(R128_DST_PITCH_OFFSET_C, 11));
+	OUT_RING(ctx->dst_pitch_offset_c);
+	OUT_RING(ctx->dp_gui_master_cntl_c);
+	OUT_RING(ctx->sc_top_left_c);
+	OUT_RING(ctx->sc_bottom_right_c);
+	OUT_RING(ctx->z_offset_c);
+	OUT_RING(ctx->z_pitch_c);
+	OUT_RING(ctx->z_sten_cntl_c);
+	OUT_RING(ctx->tex_cntl_c);
+	OUT_RING(ctx->misc_3d_state_cntl_reg);
+	OUT_RING(ctx->texture_clr_cmp_clr_c);
+	OUT_RING(ctx->texture_clr_cmp_msk_c);
+	OUT_RING(ctx->fog_color_c);
+
+	ADVANCE_RING();
+}
+
+static __inline__ void r128_emit_setup(drm_r128_private_t *dev_priv)
+{
+	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
+	RING_LOCALS;
+	DRM_DEBUG("\n");
+
+	BEGIN_RING(3);
+
+	OUT_RING(CCE_PACKET1(R128_SETUP_CNTL, R128_PM4_VC_FPU_SETUP));
+	OUT_RING(ctx->setup_cntl);
+	OUT_RING(ctx->pm4_vc_fpu_setup);
+
+	ADVANCE_RING();
+}
+
+static __inline__ void r128_emit_masks(drm_r128_private_t *dev_priv)
+{
+	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
+	RING_LOCALS;
+	DRM_DEBUG("\n");
+
+	BEGIN_RING(5);
+
+	OUT_RING(CCE_PACKET0(R128_DP_WRITE_MASK, 0));
+	OUT_RING(ctx->dp_write_mask);
+
+	OUT_RING(CCE_PACKET0(R128_STEN_REF_MASK_C, 1));
+	OUT_RING(ctx->sten_ref_mask_c);
+	OUT_RING(ctx->plane_3d_mask_c);
+
+	ADVANCE_RING();
+}
+
+static __inline__ void r128_emit_window(drm_r128_private_t *dev_priv)
+{
+	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
+	RING_LOCALS;
+	DRM_DEBUG("\n");
+
+	BEGIN_RING(2);
+
+	OUT_RING(CCE_PACKET0(R128_WINDOW_XY_OFFSET, 0));
+	OUT_RING(ctx->window_xy_offset);
+
+	ADVANCE_RING();
+}
+
+static __inline__ void r128_emit_tex0(drm_r128_private_t *dev_priv)
+{
+	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_r128_context_regs_t *ctx = &sarea_priv->context_state;
+	drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[0];
+	int i;
+	RING_LOCALS;
+	DRM_DEBUG("\n");
+
+	BEGIN_RING(7 + R128_MAX_TEXTURE_LEVELS);
+
+	OUT_RING(CCE_PACKET0(R128_PRIM_TEX_CNTL_C,
+			     2 + R128_MAX_TEXTURE_LEVELS));
+	OUT_RING(tex->tex_cntl);
+	OUT_RING(tex->tex_combine_cntl);
+	OUT_RING(ctx->tex_size_pitch_c);
+	for (i = 0; i < R128_MAX_TEXTURE_LEVELS; i++)
+		OUT_RING(tex->tex_offset[i]);
+
+	OUT_RING(CCE_PACKET0(R128_CONSTANT_COLOR_C, 1));
+	OUT_RING(ctx->constant_color_c);
+	OUT_RING(tex->tex_border_color);
+
+	ADVANCE_RING();
+}
+
+static __inline__ void r128_emit_tex1(drm_r128_private_t *dev_priv)
+{
+	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[1];
+	int i;
+	RING_LOCALS;
+	DRM_DEBUG("\n");
+
+	BEGIN_RING(5 + R128_MAX_TEXTURE_LEVELS);
+
+	OUT_RING(CCE_PACKET0(R128_SEC_TEX_CNTL_C, 1 + R128_MAX_TEXTURE_LEVELS));
+	OUT_RING(tex->tex_cntl);
+	OUT_RING(tex->tex_combine_cntl);
+	for (i = 0; i < R128_MAX_TEXTURE_LEVELS; i++)
+		OUT_RING(tex->tex_offset[i]);
+
+	OUT_RING(CCE_PACKET0(R128_SEC_TEXTURE_BORDER_COLOR_C, 0));
+	OUT_RING(tex->tex_border_color);
+
+	ADVANCE_RING();
+}
+
+static void r128_emit_state(drm_r128_private_t *dev_priv)
+{
+	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	unsigned int dirty = sarea_priv->dirty;
+
+	DRM_DEBUG("dirty=0x%08x\n", dirty);
+
+	if (dirty & R128_UPLOAD_CORE) {
+		r128_emit_core(dev_priv);
+		sarea_priv->dirty &= ~R128_UPLOAD_CORE;
+	}
+
+	if (dirty & R128_UPLOAD_CONTEXT) {
+		r128_emit_context(dev_priv);
+		sarea_priv->dirty &= ~R128_UPLOAD_CONTEXT;
+	}
+
+	if (dirty & R128_UPLOAD_SETUP) {
+		r128_emit_setup(dev_priv);
+		sarea_priv->dirty &= ~R128_UPLOAD_SETUP;
+	}
+
+	if (dirty & R128_UPLOAD_MASKS) {
+		r128_emit_masks(dev_priv);
+		sarea_priv->dirty &= ~R128_UPLOAD_MASKS;
+	}
+
+	if (dirty & R128_UPLOAD_WINDOW) {
+		r128_emit_window(dev_priv);
+		sarea_priv->dirty &= ~R128_UPLOAD_WINDOW;
+	}
+
+	if (dirty & R128_UPLOAD_TEX0) {
+		r128_emit_tex0(dev_priv);
+		sarea_priv->dirty &= ~R128_UPLOAD_TEX0;
+	}
+
+	if (dirty & R128_UPLOAD_TEX1) {
+		r128_emit_tex1(dev_priv);
+		sarea_priv->dirty &= ~R128_UPLOAD_TEX1;
+	}
+
+	/* Turn off the texture cache flushing */
+	sarea_priv->context_state.tex_cntl_c &= ~R128_TEX_CACHE_FLUSH;
+
+	sarea_priv->dirty &= ~R128_REQUIRE_QUIESCENCE;
+}
+
+#if R128_PERFORMANCE_BOXES
+/* ================================================================
+ * Performance monitoring functions
+ */
+
+static void r128_clear_box(drm_r128_private_t *dev_priv,
+			   int x, int y, int w, int h, int r, int g, int b)
+{
+	u32 pitch, offset;
+	u32 fb_bpp, color;
+	RING_LOCALS;
+
+	switch (dev_priv->fb_bpp) {
+	case 16:
+		fb_bpp = R128_GMC_DST_16BPP;
+		color = (((r & 0xf8) << 8) |
+			 ((g & 0xfc) << 3) | ((b & 0xf8) >> 3));
+		break;
+	case 24:
+		fb_bpp = R128_GMC_DST_24BPP;
+		color = ((r << 16) | (g << 8) | b);
+		break;
+	case 32:
+		fb_bpp = R128_GMC_DST_32BPP;
+		color = (((0xff) << 24) | (r << 16) | (g << 8) | b);
+		break;
+	default:
+		return;
+	}
+
+	offset = dev_priv->back_offset;
+	pitch = dev_priv->back_pitch >> 3;
+
+	BEGIN_RING(6);
+
+	OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
+	OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
+		 R128_GMC_BRUSH_SOLID_COLOR |
+		 fb_bpp |
+		 R128_GMC_SRC_DATATYPE_COLOR |
+		 R128_ROP3_P |
+		 R128_GMC_CLR_CMP_CNTL_DIS | R128_GMC_AUX_CLIP_DIS);
+
+	OUT_RING((pitch << 21) | (offset >> 5));
+	OUT_RING(color);
+
+	OUT_RING((x << 16) | y);
+	OUT_RING((w << 16) | h);
+
+	ADVANCE_RING();
+}
+
+static void r128_cce_performance_boxes(drm_r128_private_t *dev_priv)
+{
+	if (atomic_read(&dev_priv->idle_count) == 0)
+		r128_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0);
+	else
+		atomic_set(&dev_priv->idle_count, 0);
+}
+
+#endif
+
+/* ================================================================
+ * CCE command dispatch functions
+ */
+
+static void r128_print_dirty(const char *msg, unsigned int flags)
+{
+	DRM_INFO("%s: (0x%x) %s%s%s%s%s%s%s%s%s\n",
+		 msg,
+		 flags,
+		 (flags & R128_UPLOAD_CORE) ? "core, " : "",
+		 (flags & R128_UPLOAD_CONTEXT) ? "context, " : "",
+		 (flags & R128_UPLOAD_SETUP) ? "setup, " : "",
+		 (flags & R128_UPLOAD_TEX0) ? "tex0, " : "",
+		 (flags & R128_UPLOAD_TEX1) ? "tex1, " : "",
+		 (flags & R128_UPLOAD_MASKS) ? "masks, " : "",
+		 (flags & R128_UPLOAD_WINDOW) ? "window, " : "",
+		 (flags & R128_UPLOAD_CLIPRECTS) ? "cliprects, " : "",
+		 (flags & R128_REQUIRE_QUIESCENCE) ? "quiescence, " : "");
+}
+
+static void r128_cce_dispatch_clear(struct drm_device *dev,
+				    drm_r128_clear_t *clear)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	int nbox = sarea_priv->nbox;
+	struct drm_clip_rect *pbox = sarea_priv->boxes;
+	unsigned int flags = clear->flags;
+	int i;
+	RING_LOCALS;
+	DRM_DEBUG("\n");
+
+	if (dev_priv->page_flipping && dev_priv->current_page == 1) {
+		unsigned int tmp = flags;
+
+		flags &= ~(R128_FRONT | R128_BACK);
+		if (tmp & R128_FRONT)
+			flags |= R128_BACK;
+		if (tmp & R128_BACK)
+			flags |= R128_FRONT;
+	}
+
+	for (i = 0; i < nbox; i++) {
+		int x = pbox[i].x1;
+		int y = pbox[i].y1;
+		int w = pbox[i].x2 - x;
+		int h = pbox[i].y2 - y;
+
+		DRM_DEBUG("dispatch clear %d,%d-%d,%d flags 0x%x\n",
+			  pbox[i].x1, pbox[i].y1, pbox[i].x2,
+			  pbox[i].y2, flags);
+
+		if (flags & (R128_FRONT | R128_BACK)) {
+			BEGIN_RING(2);
+
+			OUT_RING(CCE_PACKET0(R128_DP_WRITE_MASK, 0));
+			OUT_RING(clear->color_mask);
+
+			ADVANCE_RING();
+		}
+
+		if (flags & R128_FRONT) {
+			BEGIN_RING(6);
+
+			OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
+			OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
+				 R128_GMC_BRUSH_SOLID_COLOR |
+				 (dev_priv->color_fmt << 8) |
+				 R128_GMC_SRC_DATATYPE_COLOR |
+				 R128_ROP3_P |
+				 R128_GMC_CLR_CMP_CNTL_DIS |
+				 R128_GMC_AUX_CLIP_DIS);
+
+			OUT_RING(dev_priv->front_pitch_offset_c);
+			OUT_RING(clear->clear_color);
+
+			OUT_RING((x << 16) | y);
+			OUT_RING((w << 16) | h);
+
+			ADVANCE_RING();
+		}
+
+		if (flags & R128_BACK) {
+			BEGIN_RING(6);
+
+			OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
+			OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
+				 R128_GMC_BRUSH_SOLID_COLOR |
+				 (dev_priv->color_fmt << 8) |
+				 R128_GMC_SRC_DATATYPE_COLOR |
+				 R128_ROP3_P |
+				 R128_GMC_CLR_CMP_CNTL_DIS |
+				 R128_GMC_AUX_CLIP_DIS);
+
+			OUT_RING(dev_priv->back_pitch_offset_c);
+			OUT_RING(clear->clear_color);
+
+			OUT_RING((x << 16) | y);
+			OUT_RING((w << 16) | h);
+
+			ADVANCE_RING();
+		}
+
+		if (flags & R128_DEPTH) {
+			BEGIN_RING(6);
+
+			OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
+			OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
+				 R128_GMC_BRUSH_SOLID_COLOR |
+				 (dev_priv->depth_fmt << 8) |
+				 R128_GMC_SRC_DATATYPE_COLOR |
+				 R128_ROP3_P |
+				 R128_GMC_CLR_CMP_CNTL_DIS |
+				 R128_GMC_AUX_CLIP_DIS | R128_GMC_WR_MSK_DIS);
+
+			OUT_RING(dev_priv->depth_pitch_offset_c);
+			OUT_RING(clear->clear_depth);
+
+			OUT_RING((x << 16) | y);
+			OUT_RING((w << 16) | h);
+
+			ADVANCE_RING();
+		}
+	}
+}
+
+static void r128_cce_dispatch_swap(struct drm_device *dev)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	int nbox = sarea_priv->nbox;
+	struct drm_clip_rect *pbox = sarea_priv->boxes;
+	int i;
+	RING_LOCALS;
+	DRM_DEBUG("\n");
+
+#if R128_PERFORMANCE_BOXES
+	/* Do some trivial performance monitoring...
+	 */
+	r128_cce_performance_boxes(dev_priv);
+#endif
+
+	for (i = 0; i < nbox; i++) {
+		int x = pbox[i].x1;
+		int y = pbox[i].y1;
+		int w = pbox[i].x2 - x;
+		int h = pbox[i].y2 - y;
+
+		BEGIN_RING(7);
+
+		OUT_RING(CCE_PACKET3(R128_CNTL_BITBLT_MULTI, 5));
+		OUT_RING(R128_GMC_SRC_PITCH_OFFSET_CNTL |
+			 R128_GMC_DST_PITCH_OFFSET_CNTL |
+			 R128_GMC_BRUSH_NONE |
+			 (dev_priv->color_fmt << 8) |
+			 R128_GMC_SRC_DATATYPE_COLOR |
+			 R128_ROP3_S |
+			 R128_DP_SRC_SOURCE_MEMORY |
+			 R128_GMC_CLR_CMP_CNTL_DIS |
+			 R128_GMC_AUX_CLIP_DIS | R128_GMC_WR_MSK_DIS);
+
+		/* Make this work even if front & back are flipped:
+		 */
+		if (dev_priv->current_page == 0) {
+			OUT_RING(dev_priv->back_pitch_offset_c);
+			OUT_RING(dev_priv->front_pitch_offset_c);
+		} else {
+			OUT_RING(dev_priv->front_pitch_offset_c);
+			OUT_RING(dev_priv->back_pitch_offset_c);
+		}
+
+		OUT_RING((x << 16) | y);
+		OUT_RING((x << 16) | y);
+		OUT_RING((w << 16) | h);
+
+		ADVANCE_RING();
+	}
+
+	/* Increment the frame counter.  The client-side 3D driver must
+	 * throttle the framerate by waiting for this value before
+	 * performing the swapbuffer ioctl.
+	 */
+	dev_priv->sarea_priv->last_frame++;
+
+	BEGIN_RING(2);
+
+	OUT_RING(CCE_PACKET0(R128_LAST_FRAME_REG, 0));
+	OUT_RING(dev_priv->sarea_priv->last_frame);
+
+	ADVANCE_RING();
+}
+
+static void r128_cce_dispatch_flip(struct drm_device *dev)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	RING_LOCALS;
+	DRM_DEBUG("page=%d pfCurrentPage=%d\n",
+		  dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage);
+
+#if R128_PERFORMANCE_BOXES
+	/* Do some trivial performance monitoring...
+	 */
+	r128_cce_performance_boxes(dev_priv);
+#endif
+
+	BEGIN_RING(4);
+
+	R128_WAIT_UNTIL_PAGE_FLIPPED();
+	OUT_RING(CCE_PACKET0(R128_CRTC_OFFSET, 0));
+
+	if (dev_priv->current_page == 0)
+		OUT_RING(dev_priv->back_offset);
+	else
+		OUT_RING(dev_priv->front_offset);
+
+	ADVANCE_RING();
+
+	/* Increment the frame counter.  The client-side 3D driver must
+	 * throttle the framerate by waiting for this value before
+	 * performing the swapbuffer ioctl.
+	 */
+	dev_priv->sarea_priv->last_frame++;
+	dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page =
+	    1 - dev_priv->current_page;
+
+	BEGIN_RING(2);
+
+	OUT_RING(CCE_PACKET0(R128_LAST_FRAME_REG, 0));
+	OUT_RING(dev_priv->sarea_priv->last_frame);
+
+	ADVANCE_RING();
+}
+
+static void r128_cce_dispatch_vertex(struct drm_device *dev, struct drm_buf *buf)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_r128_buf_priv_t *buf_priv = buf->dev_private;
+	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	int format = sarea_priv->vc_format;
+	int offset = buf->bus_address;
+	int size = buf->used;
+	int prim = buf_priv->prim;
+	int i = 0;
+	RING_LOCALS;
+	DRM_DEBUG("buf=%d nbox=%d\n", buf->idx, sarea_priv->nbox);
+
+	if (0)
+		r128_print_dirty("dispatch_vertex", sarea_priv->dirty);
+
+	if (buf->used) {
+		buf_priv->dispatched = 1;
+
+		if (sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS)
+			r128_emit_state(dev_priv);
+
+		do {
+			/* Emit the next set of up to three cliprects */
+			if (i < sarea_priv->nbox) {
+				r128_emit_clip_rects(dev_priv,
+						     &sarea_priv->boxes[i],
+						     sarea_priv->nbox - i);
+			}
+
+			/* Emit the vertex buffer rendering commands */
+			BEGIN_RING(5);
+
+			OUT_RING(CCE_PACKET3(R128_3D_RNDR_GEN_INDX_PRIM, 3));
+			OUT_RING(offset);
+			OUT_RING(size);
+			OUT_RING(format);
+			OUT_RING(prim | R128_CCE_VC_CNTL_PRIM_WALK_LIST |
+				 (size << R128_CCE_VC_CNTL_NUM_SHIFT));
+
+			ADVANCE_RING();
+
+			i += 3;
+		} while (i < sarea_priv->nbox);
+	}
+
+	if (buf_priv->discard) {
+		buf_priv->age = dev_priv->sarea_priv->last_dispatch;
+
+		/* Emit the vertex buffer age */
+		BEGIN_RING(2);
+
+		OUT_RING(CCE_PACKET0(R128_LAST_DISPATCH_REG, 0));
+		OUT_RING(buf_priv->age);
+
+		ADVANCE_RING();
+
+		buf->pending = 1;
+		buf->used = 0;
+		/* FIXME: Check dispatched field */
+		buf_priv->dispatched = 0;
+	}
+
+	dev_priv->sarea_priv->last_dispatch++;
+
+	sarea_priv->dirty &= ~R128_UPLOAD_CLIPRECTS;
+	sarea_priv->nbox = 0;
+}
+
+static void r128_cce_dispatch_indirect(struct drm_device *dev,
+				       struct drm_buf *buf, int start, int end)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_r128_buf_priv_t *buf_priv = buf->dev_private;
+	RING_LOCALS;
+	DRM_DEBUG("indirect: buf=%d s=0x%x e=0x%x\n", buf->idx, start, end);
+
+	if (start != end) {
+		int offset = buf->bus_address + start;
+		int dwords = (end - start + 3) / sizeof(u32);
+
+		/* Indirect buffer data must be an even number of
+		 * dwords, so if we've been given an odd number we must
+		 * pad the data with a Type-2 CCE packet.
+		 */
+		if (dwords & 1) {
+			u32 *data = (u32 *)
+			    ((char *)dev->agp_buffer_map->handle
+			     + buf->offset + start);
+			data[dwords++] = cpu_to_le32(R128_CCE_PACKET2);
+		}
+
+		buf_priv->dispatched = 1;
+
+		/* Fire off the indirect buffer */
+		BEGIN_RING(3);
+
+		OUT_RING(CCE_PACKET0(R128_PM4_IW_INDOFF, 1));
+		OUT_RING(offset);
+		OUT_RING(dwords);
+
+		ADVANCE_RING();
+	}
+
+	if (buf_priv->discard) {
+		buf_priv->age = dev_priv->sarea_priv->last_dispatch;
+
+		/* Emit the indirect buffer age */
+		BEGIN_RING(2);
+
+		OUT_RING(CCE_PACKET0(R128_LAST_DISPATCH_REG, 0));
+		OUT_RING(buf_priv->age);
+
+		ADVANCE_RING();
+
+		buf->pending = 1;
+		buf->used = 0;
+		/* FIXME: Check dispatched field */
+		buf_priv->dispatched = 0;
+	}
+
+	dev_priv->sarea_priv->last_dispatch++;
+}
+
+static void r128_cce_dispatch_indices(struct drm_device *dev,
+				      struct drm_buf *buf,
+				      int start, int end, int count)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_r128_buf_priv_t *buf_priv = buf->dev_private;
+	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	int format = sarea_priv->vc_format;
+	int offset = dev->agp_buffer_map->offset - dev_priv->cce_buffers_offset;
+	int prim = buf_priv->prim;
+	u32 *data;
+	int dwords;
+	int i = 0;
+	RING_LOCALS;
+	DRM_DEBUG("indices: s=%d e=%d c=%d\n", start, end, count);
+
+	if (0)
+		r128_print_dirty("dispatch_indices", sarea_priv->dirty);
+
+	if (start != end) {
+		buf_priv->dispatched = 1;
+
+		if (sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS)
+			r128_emit_state(dev_priv);
+
+		dwords = (end - start + 3) / sizeof(u32);
+
+		data = (u32 *) ((char *)dev->agp_buffer_map->handle
+				+ buf->offset + start);
+
+		data[0] = cpu_to_le32(CCE_PACKET3(R128_3D_RNDR_GEN_INDX_PRIM,
+						  dwords - 2));
+
+		data[1] = cpu_to_le32(offset);
+		data[2] = cpu_to_le32(R128_MAX_VB_VERTS);
+		data[3] = cpu_to_le32(format);
+		data[4] = cpu_to_le32((prim | R128_CCE_VC_CNTL_PRIM_WALK_IND |
+				       (count << 16)));
+
+		if (count & 0x1) {
+#ifdef __LITTLE_ENDIAN
+			data[dwords - 1] &= 0x0000ffff;
+#else
+			data[dwords - 1] &= 0xffff0000;
+#endif
+		}
+
+		do {
+			/* Emit the next set of up to three cliprects */
+			if (i < sarea_priv->nbox) {
+				r128_emit_clip_rects(dev_priv,
+						     &sarea_priv->boxes[i],
+						     sarea_priv->nbox - i);
+			}
+
+			r128_cce_dispatch_indirect(dev, buf, start, end);
+
+			i += 3;
+		} while (i < sarea_priv->nbox);
+	}
+
+	if (buf_priv->discard) {
+		buf_priv->age = dev_priv->sarea_priv->last_dispatch;
+
+		/* Emit the vertex buffer age */
+		BEGIN_RING(2);
+
+		OUT_RING(CCE_PACKET0(R128_LAST_DISPATCH_REG, 0));
+		OUT_RING(buf_priv->age);
+
+		ADVANCE_RING();
+
+		buf->pending = 1;
+		/* FIXME: Check dispatched field */
+		buf_priv->dispatched = 0;
+	}
+
+	dev_priv->sarea_priv->last_dispatch++;
+
+	sarea_priv->dirty &= ~R128_UPLOAD_CLIPRECTS;
+	sarea_priv->nbox = 0;
+}
+
+static int r128_cce_dispatch_blit(struct drm_device *dev,
+				  struct drm_file *file_priv,
+				  drm_r128_blit_t *blit)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	struct drm_device_dma *dma = dev->dma;
+	struct drm_buf *buf;
+	drm_r128_buf_priv_t *buf_priv;
+	u32 *data;
+	int dword_shift, dwords;
+	RING_LOCALS;
+	DRM_DEBUG("\n");
+
+	/* The compiler won't optimize away a division by a variable,
+	 * even if the only legal values are powers of two.  Thus, we'll
+	 * use a shift instead.
+	 */
+	switch (blit->format) {
+	case R128_DATATYPE_ARGB8888:
+		dword_shift = 0;
+		break;
+	case R128_DATATYPE_ARGB1555:
+	case R128_DATATYPE_RGB565:
+	case R128_DATATYPE_ARGB4444:
+	case R128_DATATYPE_YVYU422:
+	case R128_DATATYPE_VYUY422:
+		dword_shift = 1;
+		break;
+	case R128_DATATYPE_CI8:
+	case R128_DATATYPE_RGB8:
+		dword_shift = 2;
+		break;
+	default:
+		DRM_ERROR("invalid blit format %d\n", blit->format);
+		return -EINVAL;
+	}
+
+	/* Flush the pixel cache, and mark the contents as Read Invalid.
+	 * This ensures no pixel data gets mixed up with the texture
+	 * data from the host data blit, otherwise part of the texture
+	 * image may be corrupted.
+	 */
+	BEGIN_RING(2);
+
+	OUT_RING(CCE_PACKET0(R128_PC_GUI_CTLSTAT, 0));
+	OUT_RING(R128_PC_RI_GUI | R128_PC_FLUSH_GUI);
+
+	ADVANCE_RING();
+
+	/* Dispatch the indirect buffer.
+	 */
+	buf = dma->buflist[blit->idx];
+	buf_priv = buf->dev_private;
+
+	if (buf->file_priv != file_priv) {
+		DRM_ERROR("process %d using buffer owned by %p\n",
+			  task_pid_nr(current), buf->file_priv);
+		return -EINVAL;
+	}
+	if (buf->pending) {
+		DRM_ERROR("sending pending buffer %d\n", blit->idx);
+		return -EINVAL;
+	}
+
+	buf_priv->discard = 1;
+
+	dwords = (blit->width * blit->height) >> dword_shift;
+
+	data = (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset);
+
+	data[0] = cpu_to_le32(CCE_PACKET3(R128_CNTL_HOSTDATA_BLT, dwords + 6));
+	data[1] = cpu_to_le32((R128_GMC_DST_PITCH_OFFSET_CNTL |
+			       R128_GMC_BRUSH_NONE |
+			       (blit->format << 8) |
+			       R128_GMC_SRC_DATATYPE_COLOR |
+			       R128_ROP3_S |
+			       R128_DP_SRC_SOURCE_HOST_DATA |
+			       R128_GMC_CLR_CMP_CNTL_DIS |
+			       R128_GMC_AUX_CLIP_DIS | R128_GMC_WR_MSK_DIS));
+
+	data[2] = cpu_to_le32((blit->pitch << 21) | (blit->offset >> 5));
+	data[3] = cpu_to_le32(0xffffffff);
+	data[4] = cpu_to_le32(0xffffffff);
+	data[5] = cpu_to_le32((blit->y << 16) | blit->x);
+	data[6] = cpu_to_le32((blit->height << 16) | blit->width);
+	data[7] = cpu_to_le32(dwords);
+
+	buf->used = (dwords + 8) * sizeof(u32);
+
+	r128_cce_dispatch_indirect(dev, buf, 0, buf->used);
+
+	/* Flush the pixel cache after the blit completes.  This ensures
+	 * the texture data is written out to memory before rendering
+	 * continues.
+	 */
+	BEGIN_RING(2);
+
+	OUT_RING(CCE_PACKET0(R128_PC_GUI_CTLSTAT, 0));
+	OUT_RING(R128_PC_FLUSH_GUI);
+
+	ADVANCE_RING();
+
+	return 0;
+}
+
+/* ================================================================
+ * Tiled depth buffer management
+ *
+ * FIXME: These should all set the destination write mask for when we
+ * have hardware stencil support.
+ */
+
+static int r128_cce_dispatch_write_span(struct drm_device *dev,
+					drm_r128_depth_t *depth)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	int count, x, y;
+	u32 *buffer;
+	u8 *mask;
+	int i, buffer_size, mask_size;
+	RING_LOCALS;
+	DRM_DEBUG("\n");
+
+	count = depth->n;
+	if (count > 4096 || count <= 0)
+		return -EMSGSIZE;
+
+	if (copy_from_user(&x, depth->x, sizeof(x)))
+		return -EFAULT;
+	if (copy_from_user(&y, depth->y, sizeof(y)))
+		return -EFAULT;
+
+	buffer_size = depth->n * sizeof(u32);
+	buffer = memdup_user(depth->buffer, buffer_size);
+	if (IS_ERR(buffer))
+		return PTR_ERR(buffer);
+
+	mask_size = depth->n;
+	if (depth->mask) {
+		mask = memdup_user(depth->mask, mask_size);
+		if (IS_ERR(mask)) {
+			kfree(buffer);
+			return PTR_ERR(mask);
+		}
+
+		for (i = 0; i < count; i++, x++) {
+			if (mask[i]) {
+				BEGIN_RING(6);
+
+				OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
+				OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
+					 R128_GMC_BRUSH_SOLID_COLOR |
+					 (dev_priv->depth_fmt << 8) |
+					 R128_GMC_SRC_DATATYPE_COLOR |
+					 R128_ROP3_P |
+					 R128_GMC_CLR_CMP_CNTL_DIS |
+					 R128_GMC_WR_MSK_DIS);
+
+				OUT_RING(dev_priv->depth_pitch_offset_c);
+				OUT_RING(buffer[i]);
+
+				OUT_RING((x << 16) | y);
+				OUT_RING((1 << 16) | 1);
+
+				ADVANCE_RING();
+			}
+		}
+
+		kfree(mask);
+	} else {
+		for (i = 0; i < count; i++, x++) {
+			BEGIN_RING(6);
+
+			OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
+			OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
+				 R128_GMC_BRUSH_SOLID_COLOR |
+				 (dev_priv->depth_fmt << 8) |
+				 R128_GMC_SRC_DATATYPE_COLOR |
+				 R128_ROP3_P |
+				 R128_GMC_CLR_CMP_CNTL_DIS |
+				 R128_GMC_WR_MSK_DIS);
+
+			OUT_RING(dev_priv->depth_pitch_offset_c);
+			OUT_RING(buffer[i]);
+
+			OUT_RING((x << 16) | y);
+			OUT_RING((1 << 16) | 1);
+
+			ADVANCE_RING();
+		}
+	}
+
+	kfree(buffer);
+
+	return 0;
+}
+
+static int r128_cce_dispatch_write_pixels(struct drm_device *dev,
+					  drm_r128_depth_t *depth)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	int count, *x, *y;
+	u32 *buffer;
+	u8 *mask;
+	int i, xbuf_size, ybuf_size, buffer_size, mask_size;
+	RING_LOCALS;
+	DRM_DEBUG("\n");
+
+	count = depth->n;
+	if (count > 4096 || count <= 0)
+		return -EMSGSIZE;
+
+	xbuf_size = count * sizeof(*x);
+	ybuf_size = count * sizeof(*y);
+	x = memdup_user(depth->x, xbuf_size);
+	if (IS_ERR(x))
+		return PTR_ERR(x);
+	y = memdup_user(depth->y, ybuf_size);
+	if (IS_ERR(y)) {
+		kfree(x);
+		return PTR_ERR(y);
+	}
+	buffer_size = depth->n * sizeof(u32);
+	buffer = memdup_user(depth->buffer, buffer_size);
+	if (IS_ERR(buffer)) {
+		kfree(x);
+		kfree(y);
+		return PTR_ERR(buffer);
+	}
+
+	if (depth->mask) {
+		mask_size = depth->n;
+		mask = memdup_user(depth->mask, mask_size);
+		if (IS_ERR(mask)) {
+			kfree(x);
+			kfree(y);
+			kfree(buffer);
+			return PTR_ERR(mask);
+		}
+
+		for (i = 0; i < count; i++) {
+			if (mask[i]) {
+				BEGIN_RING(6);
+
+				OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
+				OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
+					 R128_GMC_BRUSH_SOLID_COLOR |
+					 (dev_priv->depth_fmt << 8) |
+					 R128_GMC_SRC_DATATYPE_COLOR |
+					 R128_ROP3_P |
+					 R128_GMC_CLR_CMP_CNTL_DIS |
+					 R128_GMC_WR_MSK_DIS);
+
+				OUT_RING(dev_priv->depth_pitch_offset_c);
+				OUT_RING(buffer[i]);
+
+				OUT_RING((x[i] << 16) | y[i]);
+				OUT_RING((1 << 16) | 1);
+
+				ADVANCE_RING();
+			}
+		}
+
+		kfree(mask);
+	} else {
+		for (i = 0; i < count; i++) {
+			BEGIN_RING(6);
+
+			OUT_RING(CCE_PACKET3(R128_CNTL_PAINT_MULTI, 4));
+			OUT_RING(R128_GMC_DST_PITCH_OFFSET_CNTL |
+				 R128_GMC_BRUSH_SOLID_COLOR |
+				 (dev_priv->depth_fmt << 8) |
+				 R128_GMC_SRC_DATATYPE_COLOR |
+				 R128_ROP3_P |
+				 R128_GMC_CLR_CMP_CNTL_DIS |
+				 R128_GMC_WR_MSK_DIS);
+
+			OUT_RING(dev_priv->depth_pitch_offset_c);
+			OUT_RING(buffer[i]);
+
+			OUT_RING((x[i] << 16) | y[i]);
+			OUT_RING((1 << 16) | 1);
+
+			ADVANCE_RING();
+		}
+	}
+
+	kfree(x);
+	kfree(y);
+	kfree(buffer);
+
+	return 0;
+}
+
+static int r128_cce_dispatch_read_span(struct drm_device *dev,
+				       drm_r128_depth_t *depth)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	int count, x, y;
+	RING_LOCALS;
+	DRM_DEBUG("\n");
+
+	count = depth->n;
+	if (count > 4096 || count <= 0)
+		return -EMSGSIZE;
+
+	if (copy_from_user(&x, depth->x, sizeof(x)))
+		return -EFAULT;
+	if (copy_from_user(&y, depth->y, sizeof(y)))
+		return -EFAULT;
+
+	BEGIN_RING(7);
+
+	OUT_RING(CCE_PACKET3(R128_CNTL_BITBLT_MULTI, 5));
+	OUT_RING(R128_GMC_SRC_PITCH_OFFSET_CNTL |
+		 R128_GMC_DST_PITCH_OFFSET_CNTL |
+		 R128_GMC_BRUSH_NONE |
+		 (dev_priv->depth_fmt << 8) |
+		 R128_GMC_SRC_DATATYPE_COLOR |
+		 R128_ROP3_S |
+		 R128_DP_SRC_SOURCE_MEMORY |
+		 R128_GMC_CLR_CMP_CNTL_DIS | R128_GMC_WR_MSK_DIS);
+
+	OUT_RING(dev_priv->depth_pitch_offset_c);
+	OUT_RING(dev_priv->span_pitch_offset_c);
+
+	OUT_RING((x << 16) | y);
+	OUT_RING((0 << 16) | 0);
+	OUT_RING((count << 16) | 1);
+
+	ADVANCE_RING();
+
+	return 0;
+}
+
+static int r128_cce_dispatch_read_pixels(struct drm_device *dev,
+					 drm_r128_depth_t *depth)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	int count, *x, *y;
+	int i, xbuf_size, ybuf_size;
+	RING_LOCALS;
+	DRM_DEBUG("\n");
+
+	count = depth->n;
+	if (count > 4096 || count <= 0)
+		return -EMSGSIZE;
+
+	if (count > dev_priv->depth_pitch)
+		count = dev_priv->depth_pitch;
+
+	xbuf_size = count * sizeof(*x);
+	ybuf_size = count * sizeof(*y);
+	x = kmalloc(xbuf_size, GFP_KERNEL);
+	if (x == NULL)
+		return -ENOMEM;
+	y = kmalloc(ybuf_size, GFP_KERNEL);
+	if (y == NULL) {
+		kfree(x);
+		return -ENOMEM;
+	}
+	if (copy_from_user(x, depth->x, xbuf_size)) {
+		kfree(x);
+		kfree(y);
+		return -EFAULT;
+	}
+	if (copy_from_user(y, depth->y, ybuf_size)) {
+		kfree(x);
+		kfree(y);
+		return -EFAULT;
+	}
+
+	for (i = 0; i < count; i++) {
+		BEGIN_RING(7);
+
+		OUT_RING(CCE_PACKET3(R128_CNTL_BITBLT_MULTI, 5));
+		OUT_RING(R128_GMC_SRC_PITCH_OFFSET_CNTL |
+			 R128_GMC_DST_PITCH_OFFSET_CNTL |
+			 R128_GMC_BRUSH_NONE |
+			 (dev_priv->depth_fmt << 8) |
+			 R128_GMC_SRC_DATATYPE_COLOR |
+			 R128_ROP3_S |
+			 R128_DP_SRC_SOURCE_MEMORY |
+			 R128_GMC_CLR_CMP_CNTL_DIS | R128_GMC_WR_MSK_DIS);
+
+		OUT_RING(dev_priv->depth_pitch_offset_c);
+		OUT_RING(dev_priv->span_pitch_offset_c);
+
+		OUT_RING((x[i] << 16) | y[i]);
+		OUT_RING((i << 16) | 0);
+		OUT_RING((1 << 16) | 1);
+
+		ADVANCE_RING();
+	}
+
+	kfree(x);
+	kfree(y);
+
+	return 0;
+}
+
+/* ================================================================
+ * Polygon stipple
+ */
+
+static void r128_cce_dispatch_stipple(struct drm_device *dev, u32 *stipple)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	int i;
+	RING_LOCALS;
+	DRM_DEBUG("\n");
+
+	BEGIN_RING(33);
+
+	OUT_RING(CCE_PACKET0(R128_BRUSH_DATA0, 31));
+	for (i = 0; i < 32; i++)
+		OUT_RING(stipple[i]);
+
+	ADVANCE_RING();
+}
+
+/* ================================================================
+ * IOCTL functions
+ */
+
+static int r128_cce_clear(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_r128_sarea_t *sarea_priv;
+	drm_r128_clear_t *clear = data;
+	DRM_DEBUG("\n");
+
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	DEV_INIT_TEST_WITH_RETURN(dev_priv);
+
+	RING_SPACE_TEST_WITH_RETURN(dev_priv);
+
+	sarea_priv = dev_priv->sarea_priv;
+
+	if (sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS)
+		sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS;
+
+	r128_cce_dispatch_clear(dev, clear);
+	COMMIT_RING();
+
+	/* Make sure we restore the 3D state next time.
+	 */
+	dev_priv->sarea_priv->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_MASKS;
+
+	return 0;
+}
+
+static int r128_do_init_pageflip(struct drm_device *dev)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	DRM_DEBUG("\n");
+
+	dev_priv->crtc_offset = R128_READ(R128_CRTC_OFFSET);
+	dev_priv->crtc_offset_cntl = R128_READ(R128_CRTC_OFFSET_CNTL);
+
+	R128_WRITE(R128_CRTC_OFFSET, dev_priv->front_offset);
+	R128_WRITE(R128_CRTC_OFFSET_CNTL,
+		   dev_priv->crtc_offset_cntl | R128_CRTC_OFFSET_FLIP_CNTL);
+
+	dev_priv->page_flipping = 1;
+	dev_priv->current_page = 0;
+	dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
+
+	return 0;
+}
+
+static int r128_do_cleanup_pageflip(struct drm_device *dev)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	DRM_DEBUG("\n");
+
+	R128_WRITE(R128_CRTC_OFFSET, dev_priv->crtc_offset);
+	R128_WRITE(R128_CRTC_OFFSET_CNTL, dev_priv->crtc_offset_cntl);
+
+	if (dev_priv->current_page != 0) {
+		r128_cce_dispatch_flip(dev);
+		COMMIT_RING();
+	}
+
+	dev_priv->page_flipping = 0;
+	return 0;
+}
+
+/* Swapping and flipping are different operations, need different ioctls.
+ * They can & should be intermixed to support multiple 3d windows.
+ */
+
+static int r128_cce_flip(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	DRM_DEBUG("\n");
+
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	DEV_INIT_TEST_WITH_RETURN(dev_priv);
+
+	RING_SPACE_TEST_WITH_RETURN(dev_priv);
+
+	if (!dev_priv->page_flipping)
+		r128_do_init_pageflip(dev);
+
+	r128_cce_dispatch_flip(dev);
+
+	COMMIT_RING();
+	return 0;
+}
+
+static int r128_cce_swap(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
+	DRM_DEBUG("\n");
+
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	DEV_INIT_TEST_WITH_RETURN(dev_priv);
+
+	RING_SPACE_TEST_WITH_RETURN(dev_priv);
+
+	if (sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS)
+		sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS;
+
+	r128_cce_dispatch_swap(dev);
+	dev_priv->sarea_priv->dirty |= (R128_UPLOAD_CONTEXT |
+					R128_UPLOAD_MASKS);
+
+	COMMIT_RING();
+	return 0;
+}
+
+static int r128_cce_vertex(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	struct drm_device_dma *dma = dev->dma;
+	struct drm_buf *buf;
+	drm_r128_buf_priv_t *buf_priv;
+	drm_r128_vertex_t *vertex = data;
+
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	DEV_INIT_TEST_WITH_RETURN(dev_priv);
+
+	DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n",
+		  task_pid_nr(current), vertex->idx, vertex->count, vertex->discard);
+
+	if (vertex->idx < 0 || vertex->idx >= dma->buf_count) {
+		DRM_ERROR("buffer index %d (of %d max)\n",
+			  vertex->idx, dma->buf_count - 1);
+		return -EINVAL;
+	}
+	if (vertex->prim < 0 ||
+	    vertex->prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
+		DRM_ERROR("buffer prim %d\n", vertex->prim);
+		return -EINVAL;
+	}
+
+	RING_SPACE_TEST_WITH_RETURN(dev_priv);
+	VB_AGE_TEST_WITH_RETURN(dev_priv);
+
+	buf = dma->buflist[vertex->idx];
+	buf_priv = buf->dev_private;
+
+	if (buf->file_priv != file_priv) {
+		DRM_ERROR("process %d using buffer owned by %p\n",
+			  task_pid_nr(current), buf->file_priv);
+		return -EINVAL;
+	}
+	if (buf->pending) {
+		DRM_ERROR("sending pending buffer %d\n", vertex->idx);
+		return -EINVAL;
+	}
+
+	buf->used = vertex->count;
+	buf_priv->prim = vertex->prim;
+	buf_priv->discard = vertex->discard;
+
+	r128_cce_dispatch_vertex(dev, buf);
+
+	COMMIT_RING();
+	return 0;
+}
+
+static int r128_cce_indices(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	struct drm_device_dma *dma = dev->dma;
+	struct drm_buf *buf;
+	drm_r128_buf_priv_t *buf_priv;
+	drm_r128_indices_t *elts = data;
+	int count;
+
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	DEV_INIT_TEST_WITH_RETURN(dev_priv);
+
+	DRM_DEBUG("pid=%d buf=%d s=%d e=%d d=%d\n", task_pid_nr(current),
+		  elts->idx, elts->start, elts->end, elts->discard);
+
+	if (elts->idx < 0 || elts->idx >= dma->buf_count) {
+		DRM_ERROR("buffer index %d (of %d max)\n",
+			  elts->idx, dma->buf_count - 1);
+		return -EINVAL;
+	}
+	if (elts->prim < 0 ||
+	    elts->prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2) {
+		DRM_ERROR("buffer prim %d\n", elts->prim);
+		return -EINVAL;
+	}
+
+	RING_SPACE_TEST_WITH_RETURN(dev_priv);
+	VB_AGE_TEST_WITH_RETURN(dev_priv);
+
+	buf = dma->buflist[elts->idx];
+	buf_priv = buf->dev_private;
+
+	if (buf->file_priv != file_priv) {
+		DRM_ERROR("process %d using buffer owned by %p\n",
+			  task_pid_nr(current), buf->file_priv);
+		return -EINVAL;
+	}
+	if (buf->pending) {
+		DRM_ERROR("sending pending buffer %d\n", elts->idx);
+		return -EINVAL;
+	}
+
+	count = (elts->end - elts->start) / sizeof(u16);
+	elts->start -= R128_INDEX_PRIM_OFFSET;
+
+	if (elts->start & 0x7) {
+		DRM_ERROR("misaligned buffer 0x%x\n", elts->start);
+		return -EINVAL;
+	}
+	if (elts->start < buf->used) {
+		DRM_ERROR("no header 0x%x - 0x%x\n", elts->start, buf->used);
+		return -EINVAL;
+	}
+
+	buf->used = elts->end;
+	buf_priv->prim = elts->prim;
+	buf_priv->discard = elts->discard;
+
+	r128_cce_dispatch_indices(dev, buf, elts->start, elts->end, count);
+
+	COMMIT_RING();
+	return 0;
+}
+
+static int r128_cce_blit(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	struct drm_device_dma *dma = dev->dma;
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_r128_blit_t *blit = data;
+	int ret;
+
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	DEV_INIT_TEST_WITH_RETURN(dev_priv);
+
+	DRM_DEBUG("pid=%d index=%d\n", task_pid_nr(current), blit->idx);
+
+	if (blit->idx < 0 || blit->idx >= dma->buf_count) {
+		DRM_ERROR("buffer index %d (of %d max)\n",
+			  blit->idx, dma->buf_count - 1);
+		return -EINVAL;
+	}
+
+	RING_SPACE_TEST_WITH_RETURN(dev_priv);
+	VB_AGE_TEST_WITH_RETURN(dev_priv);
+
+	ret = r128_cce_dispatch_blit(dev, file_priv, blit);
+
+	COMMIT_RING();
+	return ret;
+}
+
+int r128_cce_depth(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_r128_depth_t *depth = data;
+	int ret;
+
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	DEV_INIT_TEST_WITH_RETURN(dev_priv);
+
+	RING_SPACE_TEST_WITH_RETURN(dev_priv);
+
+	ret = -EINVAL;
+	switch (depth->func) {
+	case R128_WRITE_SPAN:
+		ret = r128_cce_dispatch_write_span(dev, depth);
+		break;
+	case R128_WRITE_PIXELS:
+		ret = r128_cce_dispatch_write_pixels(dev, depth);
+		break;
+	case R128_READ_SPAN:
+		ret = r128_cce_dispatch_read_span(dev, depth);
+		break;
+	case R128_READ_PIXELS:
+		ret = r128_cce_dispatch_read_pixels(dev, depth);
+		break;
+	}
+
+	COMMIT_RING();
+	return ret;
+}
+
+int r128_cce_stipple(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_r128_stipple_t *stipple = data;
+	u32 mask[32];
+
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	DEV_INIT_TEST_WITH_RETURN(dev_priv);
+
+	if (copy_from_user(&mask, stipple->mask, 32 * sizeof(u32)))
+		return -EFAULT;
+
+	RING_SPACE_TEST_WITH_RETURN(dev_priv);
+
+	r128_cce_dispatch_stipple(dev, mask);
+
+	COMMIT_RING();
+	return 0;
+}
+
+static int r128_cce_indirect(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	struct drm_device_dma *dma = dev->dma;
+	struct drm_buf *buf;
+	drm_r128_buf_priv_t *buf_priv;
+	drm_r128_indirect_t *indirect = data;
+#if 0
+	RING_LOCALS;
+#endif
+
+	LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+	DEV_INIT_TEST_WITH_RETURN(dev_priv);
+
+	DRM_DEBUG("idx=%d s=%d e=%d d=%d\n",
+		  indirect->idx, indirect->start, indirect->end,
+		  indirect->discard);
+
+	if (indirect->idx < 0 || indirect->idx >= dma->buf_count) {
+		DRM_ERROR("buffer index %d (of %d max)\n",
+			  indirect->idx, dma->buf_count - 1);
+		return -EINVAL;
+	}
+
+	buf = dma->buflist[indirect->idx];
+	buf_priv = buf->dev_private;
+
+	if (buf->file_priv != file_priv) {
+		DRM_ERROR("process %d using buffer owned by %p\n",
+			  task_pid_nr(current), buf->file_priv);
+		return -EINVAL;
+	}
+	if (buf->pending) {
+		DRM_ERROR("sending pending buffer %d\n", indirect->idx);
+		return -EINVAL;
+	}
+
+	if (indirect->start < buf->used) {
+		DRM_ERROR("reusing indirect: start=0x%x actual=0x%x\n",
+			  indirect->start, buf->used);
+		return -EINVAL;
+	}
+
+	RING_SPACE_TEST_WITH_RETURN(dev_priv);
+	VB_AGE_TEST_WITH_RETURN(dev_priv);
+
+	buf->used = indirect->end;
+	buf_priv->discard = indirect->discard;
+
+#if 0
+	/* Wait for the 3D stream to idle before the indirect buffer
+	 * containing 2D acceleration commands is processed.
+	 */
+	BEGIN_RING(2);
+	RADEON_WAIT_UNTIL_3D_IDLE();
+	ADVANCE_RING();
+#endif
+
+	/* Dispatch the indirect buffer full of commands from the
+	 * X server.  This is insecure and is thus only available to
+	 * privileged clients.
+	 */
+	r128_cce_dispatch_indirect(dev, buf, indirect->start, indirect->end);
+
+	COMMIT_RING();
+	return 0;
+}
+
+int r128_getparam(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+	drm_r128_private_t *dev_priv = dev->dev_private;
+	drm_r128_getparam_t *param = data;
+	int value;
+
+	DEV_INIT_TEST_WITH_RETURN(dev_priv);
+
+	DRM_DEBUG("pid=%d\n", task_pid_nr(current));
+
+	switch (param->param) {
+	case R128_PARAM_IRQ_NR:
+		value = dev->pdev->irq;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (copy_to_user(param->value, &value, sizeof(int))) {
+		DRM_ERROR("copy_to_user\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+void r128_driver_preclose(struct drm_device *dev, struct drm_file *file_priv)
+{
+	if (dev->dev_private) {
+		drm_r128_private_t *dev_priv = dev->dev_private;
+		if (dev_priv->page_flipping)
+			r128_do_cleanup_pageflip(dev);
+	}
+}
+void r128_driver_lastclose(struct drm_device *dev)
+{
+	r128_do_cleanup_cce(dev);
+}
+
+const struct drm_ioctl_desc r128_ioctls[] = {
+	DRM_IOCTL_DEF_DRV(R128_INIT, r128_cce_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+	DRM_IOCTL_DEF_DRV(R128_CCE_START, r128_cce_start, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+	DRM_IOCTL_DEF_DRV(R128_CCE_STOP, r128_cce_stop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+	DRM_IOCTL_DEF_DRV(R128_CCE_RESET, r128_cce_reset, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+	DRM_IOCTL_DEF_DRV(R128_CCE_IDLE, r128_cce_idle, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(R128_RESET, r128_engine_reset, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(R128_FULLSCREEN, r128_fullscreen, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(R128_SWAP, r128_cce_swap, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(R128_FLIP, r128_cce_flip, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(R128_CLEAR, r128_cce_clear, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(R128_VERTEX, r128_cce_vertex, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(R128_INDICES, r128_cce_indices, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(R128_BLIT, r128_cce_blit, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(R128_DEPTH, r128_cce_depth, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(R128_STIPPLE, r128_cce_stipple, DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(R128_INDIRECT, r128_cce_indirect, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+	DRM_IOCTL_DEF_DRV(R128_GETPARAM, r128_getparam, DRM_AUTH),
+};
+
+int r128_max_ioctl = ARRAY_SIZE(r128_ioctls);