4145 lines
125 KiB
Diff
4145 lines
125 KiB
Diff
mach64 driver from git://anongit.freedesktop.org/git/mesa/drm
|
|
head: c99566fb810c9d8cae5e9cd39d1772b55e2f514c
|
|
|
|
---
|
|
drivers/gpu/drm/Kconfig | 11
|
|
drivers/gpu/drm/Makefile | 1
|
|
drivers/gpu/drm/mach64/Makefile | 8
|
|
drivers/gpu/drm/Kconfig | 11
|
|
drivers/gpu/drm/Makefile | 1
|
|
drivers/gpu/drm/mach64/Makefile | 8
|
|
drivers/gpu/drm/mach64/mach64_dma.c | 1778 ++++++++++++++++++++++++++++++++++
|
|
drivers/gpu/drm/mach64/mach64_drm.h | 256 ++++
|
|
drivers/gpu/drm/mach64/mach64_drv.c | 105 ++
|
|
drivers/gpu/drm/mach64/mach64_drv.h | 859 ++++++++++++++++
|
|
drivers/gpu/drm/mach64/mach64_irq.c | 159 +++
|
|
drivers/gpu/drm/mach64/mach64_state.c | 910 +++++++++++++++++
|
|
9 files changed, 4087 insertions(+)
|
|
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/mach64/Makefile
|
|
@@ -0,0 +1,8 @@
|
|
+#
|
|
+# Makefile for the drm device driver. This driver provides support for the
|
|
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
|
+
|
|
+ccflags-y = -Iinclude/drm
|
|
+mach64-y := mach64_drv.o mach64_dma.o mach64_irq.o mach64_state.o
|
|
+
|
|
+obj-$(CONFIG_DRM_MACH64) += mach64.o
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/mach64/mach64_dma.c
|
|
@@ -0,0 +1,1778 @@
|
|
+/* mach64_dma.c -- DMA support for mach64 (Rage Pro) driver -*- linux-c -*- */
|
|
+/**
|
|
+ * \file mach64_dma.c
|
|
+ * DMA support for mach64 (Rage Pro) driver
|
|
+ *
|
|
+ * \author Gareth Hughes <gareth@valinux.com>
|
|
+ * \author Frank C. Earl <fearl@airmail.net>
|
|
+ * \author Leif Delgass <ldelgass@retinalburn.net>
|
|
+ * \author José Fonseca <j_r_fonseca@yahoo.co.uk>
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * Copyright 2000 Gareth Hughes
|
|
+ * Copyright 2002 Frank C. Earl
|
|
+ * Copyright 2002-2003 Leif Delgass
|
|
+ * 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 COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
+ */
|
|
+
|
|
+#include "drmP.h"
|
|
+#include "drm.h"
|
|
+#include "mach64_drm.h"
|
|
+#include "mach64_drv.h"
|
|
+
|
|
+/*******************************************************************/
|
|
+/** \name Engine, FIFO control */
|
|
+/*@{*/
|
|
+
|
|
+/**
|
|
+ * Waits for free entries in the FIFO.
|
|
+ *
|
|
+ * \note Most writes to Mach64 registers are automatically routed through
|
|
+ * command FIFO which is 16 entry deep. Prior to writing to any draw engine
|
|
+ * register one has to ensure that enough FIFO entries are available by calling
|
|
+ * this function. Failure to do so may cause the engine to lock.
|
|
+ *
|
|
+ * \param dev_priv pointer to device private data structure.
|
|
+ * \param entries number of free entries in the FIFO to wait for.
|
|
+ *
|
|
+ * \returns zero on success, or -EBUSY if the timeout (specificed by
|
|
+ * drm_mach64_private::usec_timeout) occurs.
|
|
+ */
|
|
+int mach64_do_wait_for_fifo(drm_mach64_private_t *dev_priv, int entries)
|
|
+{
|
|
+ int slots = 0, i;
|
|
+
|
|
+ for (i = 0; i < dev_priv->usec_timeout; i++) {
|
|
+ slots = (MACH64_READ(MACH64_FIFO_STAT) & MACH64_FIFO_SLOT_MASK);
|
|
+ if (slots <= (0x8000 >> entries))
|
|
+ return 0;
|
|
+ DRM_UDELAY(1);
|
|
+ }
|
|
+
|
|
+ DRM_INFO("failed! slots=%d entries=%d\n", slots, entries);
|
|
+ return -EBUSY;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Wait for the draw engine to be idle.
|
|
+ */
|
|
+int mach64_do_wait_for_idle(drm_mach64_private_t *dev_priv)
|
|
+{
|
|
+ int i, ret;
|
|
+
|
|
+ ret = mach64_do_wait_for_fifo(dev_priv, 16);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ for (i = 0; i < dev_priv->usec_timeout; i++) {
|
|
+ if (!(MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE))
|
|
+ return 0;
|
|
+ DRM_UDELAY(1);
|
|
+ }
|
|
+
|
|
+ DRM_INFO("failed! GUI_STAT=0x%08x\n", MACH64_READ(MACH64_GUI_STAT));
|
|
+ mach64_dump_ring_info(dev_priv);
|
|
+ return -EBUSY;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Wait for free entries in the ring buffer.
|
|
+ *
|
|
+ * The Mach64 bus master can be configured to act as a virtual FIFO, using a
|
|
+ * circular buffer (commonly referred as "ring buffer" in other drivers) with
|
|
+ * pointers to engine commands. This allows the CPU to do other things while
|
|
+ * the graphics engine is busy, i.e., DMA mode.
|
|
+ *
|
|
+ * This function should be called before writing new entries to the ring
|
|
+ * buffer.
|
|
+ *
|
|
+ * \param dev_priv pointer to device private data structure.
|
|
+ * \param n number of free entries in the ring buffer to wait for.
|
|
+ *
|
|
+ * \returns zero on success, or -EBUSY if the timeout (specificed by
|
|
+ * drm_mach64_private_t::usec_timeout) occurs.
|
|
+ *
|
|
+ * \sa mach64_dump_ring_info()
|
|
+ */
|
|
+int mach64_wait_ring(drm_mach64_private_t *dev_priv, int n)
|
|
+{
|
|
+ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < dev_priv->usec_timeout; i++) {
|
|
+ mach64_update_ring_snapshot(dev_priv);
|
|
+ if (ring->space >= n) {
|
|
+ if (i > 0)
|
|
+ DRM_DEBUG("%d usecs\n", i);
|
|
+ return 0;
|
|
+ }
|
|
+ DRM_UDELAY(1);
|
|
+ }
|
|
+
|
|
+ /* FIXME: This is being ignored... */
|
|
+ DRM_ERROR("failed!\n");
|
|
+ mach64_dump_ring_info(dev_priv);
|
|
+ return -EBUSY;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Wait until all DMA requests have been processed...
|
|
+ *
|
|
+ * \sa mach64_wait_ring()
|
|
+ */
|
|
+static int mach64_ring_idle(drm_mach64_private_t *dev_priv)
|
|
+{
|
|
+ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
|
|
+ u32 head;
|
|
+ int i;
|
|
+
|
|
+ head = ring->head;
|
|
+ i = 0;
|
|
+ while (i < dev_priv->usec_timeout) {
|
|
+ mach64_update_ring_snapshot(dev_priv);
|
|
+ if (ring->head == ring->tail &&
|
|
+ !(MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE)) {
|
|
+ if (i > 0)
|
|
+ DRM_DEBUG("%d usecs\n", i);
|
|
+ return 0;
|
|
+ }
|
|
+ if (ring->head == head) {
|
|
+ ++i;
|
|
+ } else {
|
|
+ head = ring->head;
|
|
+ i = 0;
|
|
+ }
|
|
+ DRM_UDELAY(1);
|
|
+ }
|
|
+
|
|
+ DRM_INFO("failed! GUI_STAT=0x%08x\n", MACH64_READ(MACH64_GUI_STAT));
|
|
+ mach64_dump_ring_info(dev_priv);
|
|
+ return -EBUSY;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Reset the the ring buffer descriptors.
|
|
+ *
|
|
+ * \sa mach64_do_engine_reset()
|
|
+ */
|
|
+static void mach64_ring_reset(drm_mach64_private_t *dev_priv)
|
|
+{
|
|
+ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
|
|
+
|
|
+ mach64_do_release_used_buffers(dev_priv);
|
|
+ ring->head_addr = ring->start_addr;
|
|
+ ring->head = ring->tail = 0;
|
|
+ ring->space = ring->size;
|
|
+
|
|
+ MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD,
|
|
+ ring->head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB);
|
|
+
|
|
+ dev_priv->ring_running = 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Ensure the all the queued commands will be processed.
|
|
+ */
|
|
+int mach64_do_dma_flush(drm_mach64_private_t *dev_priv)
|
|
+{
|
|
+ /* FIXME: It's not necessary to wait for idle when flushing
|
|
+ * we just need to ensure the ring will be completely processed
|
|
+ * in finite time without another ioctl
|
|
+ */
|
|
+ return mach64_ring_idle(dev_priv);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Stop all DMA activity.
|
|
+ */
|
|
+int mach64_do_dma_idle(drm_mach64_private_t *dev_priv)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ /* wait for completion */
|
|
+ if ((ret = mach64_ring_idle(dev_priv)) < 0) {
|
|
+ DRM_ERROR("failed BM_GUI_TABLE=0x%08x tail: %u\n",
|
|
+ MACH64_READ(MACH64_BM_GUI_TABLE),
|
|
+ dev_priv->ring.tail);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ mach64_ring_stop(dev_priv);
|
|
+
|
|
+ /* clean up after pass */
|
|
+ mach64_do_release_used_buffers(dev_priv);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Reset the engine. This will stop the DMA if it is running.
|
|
+ */
|
|
+int mach64_do_engine_reset(drm_mach64_private_t *dev_priv)
|
|
+{
|
|
+ u32 tmp;
|
|
+
|
|
+ DRM_DEBUG("\n");
|
|
+
|
|
+ /* Kill off any outstanding DMA transfers.
|
|
+ */
|
|
+ tmp = MACH64_READ(MACH64_BUS_CNTL);
|
|
+ MACH64_WRITE(MACH64_BUS_CNTL, tmp | MACH64_BUS_MASTER_DIS);
|
|
+
|
|
+ /* Reset the GUI engine (high to low transition).
|
|
+ */
|
|
+ tmp = MACH64_READ(MACH64_GEN_TEST_CNTL);
|
|
+ MACH64_WRITE(MACH64_GEN_TEST_CNTL, tmp & ~MACH64_GUI_ENGINE_ENABLE);
|
|
+ /* Enable the GUI engine
|
|
+ */
|
|
+ tmp = MACH64_READ(MACH64_GEN_TEST_CNTL);
|
|
+ MACH64_WRITE(MACH64_GEN_TEST_CNTL, tmp | MACH64_GUI_ENGINE_ENABLE);
|
|
+
|
|
+ /* ensure engine is not locked up by clearing any FIFO or HOST errors
|
|
+ */
|
|
+ tmp = MACH64_READ(MACH64_BUS_CNTL);
|
|
+ MACH64_WRITE(MACH64_BUS_CNTL, tmp | 0x00a00000);
|
|
+
|
|
+ /* Once GUI engine is restored, disable bus mastering */
|
|
+ MACH64_WRITE(MACH64_SRC_CNTL, 0);
|
|
+
|
|
+ /* Reset descriptor ring */
|
|
+ mach64_ring_reset(dev_priv);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*@}*/
|
|
+
|
|
+
|
|
+/*******************************************************************/
|
|
+/** \name Debugging output */
|
|
+/*@{*/
|
|
+
|
|
+/**
|
|
+ * Dump engine registers values.
|
|
+ */
|
|
+void mach64_dump_engine_info(drm_mach64_private_t *dev_priv)
|
|
+{
|
|
+ DRM_INFO("\n");
|
|
+ if (!dev_priv->is_pci) {
|
|
+ DRM_INFO(" AGP_BASE = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_AGP_BASE));
|
|
+ DRM_INFO(" AGP_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_AGP_CNTL));
|
|
+ }
|
|
+ DRM_INFO(" ALPHA_TST_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_ALPHA_TST_CNTL));
|
|
+ DRM_INFO("\n");
|
|
+ DRM_INFO(" BM_COMMAND = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_BM_COMMAND));
|
|
+ DRM_INFO("BM_FRAME_BUF_OFFSET = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_BM_FRAME_BUF_OFFSET));
|
|
+ DRM_INFO(" BM_GUI_TABLE = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_BM_GUI_TABLE));
|
|
+ DRM_INFO(" BM_STATUS = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_BM_STATUS));
|
|
+ DRM_INFO(" BM_SYSTEM_MEM_ADDR = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_BM_SYSTEM_MEM_ADDR));
|
|
+ DRM_INFO(" BM_SYSTEM_TABLE = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_BM_SYSTEM_TABLE));
|
|
+ DRM_INFO(" BUS_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_BUS_CNTL));
|
|
+ DRM_INFO("\n");
|
|
+ /* DRM_INFO( " CLOCK_CNTL = 0x%08x\n", MACH64_READ( MACH64_CLOCK_CNTL ) ); */
|
|
+ DRM_INFO(" CLR_CMP_CLR = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_CLR_CMP_CLR));
|
|
+ DRM_INFO(" CLR_CMP_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_CLR_CMP_CNTL));
|
|
+ /* DRM_INFO( " CLR_CMP_MSK = 0x%08x\n", MACH64_READ( MACH64_CLR_CMP_MSK ) ); */
|
|
+ DRM_INFO(" CONFIG_CHIP_ID = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_CONFIG_CHIP_ID));
|
|
+ DRM_INFO(" CONFIG_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_CONFIG_CNTL));
|
|
+ DRM_INFO(" CONFIG_STAT0 = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_CONFIG_STAT0));
|
|
+ DRM_INFO(" CONFIG_STAT1 = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_CONFIG_STAT1));
|
|
+ DRM_INFO(" CONFIG_STAT2 = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_CONFIG_STAT2));
|
|
+ DRM_INFO(" CRC_SIG = 0x%08x\n", MACH64_READ(MACH64_CRC_SIG));
|
|
+ DRM_INFO(" CUSTOM_MACRO_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_CUSTOM_MACRO_CNTL));
|
|
+ DRM_INFO("\n");
|
|
+ /* DRM_INFO( " DAC_CNTL = 0x%08x\n", MACH64_READ( MACH64_DAC_CNTL ) ); */
|
|
+ /* DRM_INFO( " DAC_REGS = 0x%08x\n", MACH64_READ( MACH64_DAC_REGS ) ); */
|
|
+ DRM_INFO(" DP_BKGD_CLR = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_DP_BKGD_CLR));
|
|
+ DRM_INFO(" DP_FRGD_CLR = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_DP_FRGD_CLR));
|
|
+ DRM_INFO(" DP_MIX = 0x%08x\n", MACH64_READ(MACH64_DP_MIX));
|
|
+ DRM_INFO(" DP_PIX_WIDTH = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_DP_PIX_WIDTH));
|
|
+ DRM_INFO(" DP_SRC = 0x%08x\n", MACH64_READ(MACH64_DP_SRC));
|
|
+ DRM_INFO(" DP_WRITE_MASK = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_DP_WRITE_MASK));
|
|
+ DRM_INFO(" DSP_CONFIG = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_DSP_CONFIG));
|
|
+ DRM_INFO(" DSP_ON_OFF = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_DSP_ON_OFF));
|
|
+ DRM_INFO(" DST_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_DST_CNTL));
|
|
+ DRM_INFO(" DST_OFF_PITCH = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_DST_OFF_PITCH));
|
|
+ DRM_INFO("\n");
|
|
+ /* DRM_INFO( " EXT_DAC_REGS = 0x%08x\n", MACH64_READ( MACH64_EXT_DAC_REGS ) ); */
|
|
+ DRM_INFO(" EXT_MEM_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_EXT_MEM_CNTL));
|
|
+ DRM_INFO("\n");
|
|
+ DRM_INFO(" FIFO_STAT = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_FIFO_STAT));
|
|
+ DRM_INFO("\n");
|
|
+ DRM_INFO(" GEN_TEST_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_GEN_TEST_CNTL));
|
|
+ /* DRM_INFO( " GP_IO = 0x%08x\n", MACH64_READ( MACH64_GP_IO ) ); */
|
|
+ DRM_INFO(" GUI_CMDFIFO_DATA = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_GUI_CMDFIFO_DATA));
|
|
+ DRM_INFO(" GUI_CMDFIFO_DEBUG = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_GUI_CMDFIFO_DEBUG));
|
|
+ DRM_INFO(" GUI_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_GUI_CNTL));
|
|
+ DRM_INFO(" GUI_STAT = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_GUI_STAT));
|
|
+ DRM_INFO(" GUI_TRAJ_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_GUI_TRAJ_CNTL));
|
|
+ DRM_INFO("\n");
|
|
+ DRM_INFO(" HOST_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_HOST_CNTL));
|
|
+ DRM_INFO(" HW_DEBUG = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_HW_DEBUG));
|
|
+ DRM_INFO("\n");
|
|
+ DRM_INFO(" MEM_ADDR_CONFIG = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_MEM_ADDR_CONFIG));
|
|
+ DRM_INFO(" MEM_BUF_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_MEM_BUF_CNTL));
|
|
+ DRM_INFO("\n");
|
|
+ DRM_INFO(" PAT_REG0 = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_PAT_REG0));
|
|
+ DRM_INFO(" PAT_REG1 = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_PAT_REG1));
|
|
+ DRM_INFO("\n");
|
|
+ DRM_INFO(" SC_LEFT = 0x%08x\n", MACH64_READ(MACH64_SC_LEFT));
|
|
+ DRM_INFO(" SC_RIGHT = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_SC_RIGHT));
|
|
+ DRM_INFO(" SC_TOP = 0x%08x\n", MACH64_READ(MACH64_SC_TOP));
|
|
+ DRM_INFO(" SC_BOTTOM = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_SC_BOTTOM));
|
|
+ DRM_INFO("\n");
|
|
+ DRM_INFO(" SCALE_3D_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_SCALE_3D_CNTL));
|
|
+ DRM_INFO(" SCRATCH_REG0 = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_SCRATCH_REG0));
|
|
+ DRM_INFO(" SCRATCH_REG1 = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_SCRATCH_REG1));
|
|
+ DRM_INFO(" SETUP_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_SETUP_CNTL));
|
|
+ DRM_INFO(" SRC_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_SRC_CNTL));
|
|
+ DRM_INFO("\n");
|
|
+ DRM_INFO(" TEX_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_TEX_CNTL));
|
|
+ DRM_INFO(" TEX_SIZE_PITCH = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_TEX_SIZE_PITCH));
|
|
+ DRM_INFO(" TIMER_CONFIG = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_TIMER_CONFIG));
|
|
+ DRM_INFO("\n");
|
|
+ DRM_INFO(" Z_CNTL = 0x%08x\n", MACH64_READ(MACH64_Z_CNTL));
|
|
+ DRM_INFO(" Z_OFF_PITCH = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_Z_OFF_PITCH));
|
|
+ DRM_INFO("\n");
|
|
+}
|
|
+
|
|
+#define MACH64_DUMP_CONTEXT 3
|
|
+
|
|
+/**
|
|
+ * Used by mach64_dump_ring_info() to dump the contents of the current buffer
|
|
+ * pointed by the ring head.
|
|
+ */
|
|
+static void mach64_dump_buf_info(drm_mach64_private_t *dev_priv,
|
|
+ struct drm_buf *buf)
|
|
+{
|
|
+ u32 addr = GETBUFADDR(buf);
|
|
+ u32 used = buf->used >> 2;
|
|
+ u32 sys_addr = MACH64_READ(MACH64_BM_SYSTEM_MEM_ADDR);
|
|
+ u32 *p = GETBUFPTR(buf);
|
|
+ int skipped = 0;
|
|
+
|
|
+ DRM_INFO("buffer contents:\n");
|
|
+
|
|
+ while (used) {
|
|
+ u32 reg, count;
|
|
+
|
|
+ reg = le32_to_cpu(*p++);
|
|
+ if (addr <= GETBUFADDR(buf) + MACH64_DUMP_CONTEXT * 4 ||
|
|
+ (addr >= sys_addr - MACH64_DUMP_CONTEXT * 4 &&
|
|
+ addr <= sys_addr + MACH64_DUMP_CONTEXT * 4) ||
|
|
+ addr >=
|
|
+ GETBUFADDR(buf) + buf->used - MACH64_DUMP_CONTEXT * 4) {
|
|
+ DRM_INFO("%08x: 0x%08x\n", addr, reg);
|
|
+ }
|
|
+ addr += 4;
|
|
+ used--;
|
|
+
|
|
+ count = (reg >> 16) + 1;
|
|
+ reg = reg & 0xffff;
|
|
+ reg = MMSELECT(reg);
|
|
+ while (count && used) {
|
|
+ if (addr <= GETBUFADDR(buf) + MACH64_DUMP_CONTEXT * 4 ||
|
|
+ (addr >= sys_addr - MACH64_DUMP_CONTEXT * 4 &&
|
|
+ addr <= sys_addr + MACH64_DUMP_CONTEXT * 4) ||
|
|
+ addr >=
|
|
+ GETBUFADDR(buf) + buf->used -
|
|
+ MACH64_DUMP_CONTEXT * 4) {
|
|
+ DRM_INFO("%08x: 0x%04x = 0x%08x\n", addr,
|
|
+ reg, le32_to_cpu(*p));
|
|
+ skipped = 0;
|
|
+ } else {
|
|
+ if (!skipped) {
|
|
+ DRM_INFO(" ...\n");
|
|
+ skipped = 1;
|
|
+ }
|
|
+ }
|
|
+ p++;
|
|
+ addr += 4;
|
|
+ used--;
|
|
+
|
|
+ reg += 4;
|
|
+ count--;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ DRM_INFO("\n");
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Dump the ring state and contents, including the contents of the buffer being
|
|
+ * processed by the graphics engine.
|
|
+ */
|
|
+void mach64_dump_ring_info(drm_mach64_private_t *dev_priv)
|
|
+{
|
|
+ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
|
|
+ int i, skipped;
|
|
+
|
|
+ DRM_INFO("\n");
|
|
+
|
|
+ DRM_INFO("ring contents:\n");
|
|
+ DRM_INFO(" head_addr: 0x%08x head: %u tail: %u\n\n",
|
|
+ ring->head_addr, ring->head, ring->tail);
|
|
+
|
|
+ skipped = 0;
|
|
+ for (i = 0; i < ring->size / sizeof(u32); i += 4) {
|
|
+ if (i <= MACH64_DUMP_CONTEXT * 4 ||
|
|
+ i >= ring->size / sizeof(u32) - MACH64_DUMP_CONTEXT * 4 ||
|
|
+ (i >= ring->tail - MACH64_DUMP_CONTEXT * 4 &&
|
|
+ i <= ring->tail + MACH64_DUMP_CONTEXT * 4) ||
|
|
+ (i >= ring->head - MACH64_DUMP_CONTEXT * 4 &&
|
|
+ i <= ring->head + MACH64_DUMP_CONTEXT * 4)) {
|
|
+ DRM_INFO(" 0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x%s%s\n",
|
|
+ (u32)(ring->start_addr + i * sizeof(u32)),
|
|
+ le32_to_cpu(((u32 *) ring->start)[i + 0]),
|
|
+ le32_to_cpu(((u32 *) ring->start)[i + 1]),
|
|
+ le32_to_cpu(((u32 *) ring->start)[i + 2]),
|
|
+ le32_to_cpu(((u32 *) ring->start)[i + 3]),
|
|
+ i == ring->head ? " (head)" : "",
|
|
+ i == ring->tail ? " (tail)" : "");
|
|
+ skipped = 0;
|
|
+ } else {
|
|
+ if (!skipped) {
|
|
+ DRM_INFO(" ...\n");
|
|
+ skipped = 1;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ DRM_INFO("\n");
|
|
+
|
|
+ if (ring->head >= 0 && ring->head < ring->size / sizeof(u32)) {
|
|
+ struct list_head *ptr;
|
|
+ u32 addr = le32_to_cpu(((u32 *) ring->start)[ring->head + 1]);
|
|
+
|
|
+ list_for_each(ptr, &dev_priv->pending) {
|
|
+ drm_mach64_freelist_t *entry =
|
|
+ list_entry(ptr, drm_mach64_freelist_t, list);
|
|
+ struct drm_buf *buf = entry->buf;
|
|
+
|
|
+ u32 buf_addr = GETBUFADDR(buf);
|
|
+
|
|
+ if (buf_addr <= addr && addr < buf_addr + buf->used)
|
|
+ mach64_dump_buf_info(dev_priv, buf);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ DRM_INFO("\n");
|
|
+ DRM_INFO(" BM_GUI_TABLE = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_BM_GUI_TABLE));
|
|
+ DRM_INFO("\n");
|
|
+ DRM_INFO("BM_FRAME_BUF_OFFSET = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_BM_FRAME_BUF_OFFSET));
|
|
+ DRM_INFO(" BM_SYSTEM_MEM_ADDR = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_BM_SYSTEM_MEM_ADDR));
|
|
+ DRM_INFO(" BM_COMMAND = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_BM_COMMAND));
|
|
+ DRM_INFO("\n");
|
|
+ DRM_INFO(" BM_STATUS = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_BM_STATUS));
|
|
+ DRM_INFO(" BUS_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_BUS_CNTL));
|
|
+ DRM_INFO(" FIFO_STAT = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_FIFO_STAT));
|
|
+ DRM_INFO(" GUI_STAT = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_GUI_STAT));
|
|
+ DRM_INFO(" SRC_CNTL = 0x%08x\n",
|
|
+ MACH64_READ(MACH64_SRC_CNTL));
|
|
+}
|
|
+
|
|
+/*@}*/
|
|
+
|
|
+
|
|
+/*******************************************************************/
|
|
+/** \name DMA descriptor ring macros */
|
|
+/*@{*/
|
|
+
|
|
+/**
|
|
+ * Add the end mark to the ring's new tail position.
|
|
+ *
|
|
+ * The bus master engine will keep processing the DMA buffers listed in the ring
|
|
+ * until it finds this mark, making it stop.
|
|
+ *
|
|
+ * \sa mach64_clear_dma_eol
|
|
+ */
|
|
+static __inline__ void mach64_set_dma_eol(volatile u32 *addr)
|
|
+{
|
|
+#if defined(__i386__)
|
|
+ int nr = 31;
|
|
+
|
|
+ /* Taken from include/asm-i386/bitops.h linux header */
|
|
+ __asm__ __volatile__("lock;" "btsl %1,%0":"=m"(*addr)
|
|
+ :"Ir"(nr));
|
|
+#elif defined(__powerpc__)
|
|
+ u32 old;
|
|
+ u32 mask = cpu_to_le32(MACH64_DMA_EOL);
|
|
+
|
|
+ /* Taken from the include/asm-ppc/bitops.h linux header */
|
|
+ __asm__ __volatile__("\n\
|
|
+1: lwarx %0,0,%3 \n\
|
|
+ or %0,%0,%2 \n\
|
|
+ stwcx. %0,0,%3 \n\
|
|
+ bne- 1b":"=&r"(old), "=m"(*addr)
|
|
+ :"r"(mask), "r"(addr), "m"(*addr)
|
|
+ :"cc");
|
|
+#elif defined(__alpha__)
|
|
+ u32 temp;
|
|
+ u32 mask = MACH64_DMA_EOL;
|
|
+
|
|
+ /* Taken from the include/asm-alpha/bitops.h linux header */
|
|
+ __asm__ __volatile__("1: ldl_l %0,%3\n"
|
|
+ " bis %0,%2,%0\n"
|
|
+ " stl_c %0,%1\n"
|
|
+ " beq %0,2f\n"
|
|
+ ".subsection 2\n"
|
|
+ "2: br 1b\n"
|
|
+ ".previous":"=&r"(temp), "=m"(*addr)
|
|
+ :"Ir"(mask), "m"(*addr));
|
|
+#else
|
|
+ u32 mask = cpu_to_le32(MACH64_DMA_EOL);
|
|
+
|
|
+ *addr |= mask;
|
|
+#endif
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Remove the end mark from the ring's old tail position.
|
|
+ *
|
|
+ * It should be called after calling mach64_set_dma_eol to mark the ring's new
|
|
+ * tail position.
|
|
+ *
|
|
+ * We update the end marks while the bus master engine is in operation. Since
|
|
+ * the bus master engine may potentially be reading from the same position
|
|
+ * that we write, we must change atomically to avoid having intermediary bad
|
|
+ * data.
|
|
+ */
|
|
+static __inline__ void mach64_clear_dma_eol(volatile u32 *addr)
|
|
+{
|
|
+#if defined(__i386__)
|
|
+ int nr = 31;
|
|
+
|
|
+ /* Taken from include/asm-i386/bitops.h linux header */
|
|
+ __asm__ __volatile__("lock;" "btrl %1,%0":"=m"(*addr)
|
|
+ :"Ir"(nr));
|
|
+#elif defined(__powerpc__)
|
|
+ u32 old;
|
|
+ u32 mask = cpu_to_le32(MACH64_DMA_EOL);
|
|
+
|
|
+ /* Taken from the include/asm-ppc/bitops.h linux header */
|
|
+ __asm__ __volatile__("\n\
|
|
+1: lwarx %0,0,%3 \n\
|
|
+ andc %0,%0,%2 \n\
|
|
+ stwcx. %0,0,%3 \n\
|
|
+ bne- 1b":"=&r"(old), "=m"(*addr)
|
|
+ :"r"(mask), "r"(addr), "m"(*addr)
|
|
+ :"cc");
|
|
+#elif defined(__alpha__)
|
|
+ u32 temp;
|
|
+ u32 mask = ~MACH64_DMA_EOL;
|
|
+
|
|
+ /* Taken from the include/asm-alpha/bitops.h linux header */
|
|
+ __asm__ __volatile__("1: ldl_l %0,%3\n"
|
|
+ " and %0,%2,%0\n"
|
|
+ " stl_c %0,%1\n"
|
|
+ " beq %0,2f\n"
|
|
+ ".subsection 2\n"
|
|
+ "2: br 1b\n"
|
|
+ ".previous":"=&r"(temp), "=m"(*addr)
|
|
+ :"Ir"(mask), "m"(*addr));
|
|
+#else
|
|
+ u32 mask = cpu_to_le32(~MACH64_DMA_EOL);
|
|
+
|
|
+ *addr &= mask;
|
|
+#endif
|
|
+}
|
|
+
|
|
+#define RING_LOCALS \
|
|
+ int _ring_tail, _ring_write; unsigned int _ring_mask; volatile u32 *_ring
|
|
+
|
|
+#define RING_WRITE_OFS _ring_write
|
|
+
|
|
+#define BEGIN_RING(n) \
|
|
+ do { \
|
|
+ if (MACH64_VERBOSE) { \
|
|
+ DRM_INFO( "BEGIN_RING( %d ) \n", \
|
|
+ (n) ); \
|
|
+ } \
|
|
+ if (dev_priv->ring.space <= (n) * sizeof(u32)) { \
|
|
+ int ret; \
|
|
+ if ((ret = mach64_wait_ring( dev_priv, (n) * sizeof(u32))) < 0 ) { \
|
|
+ DRM_ERROR( "wait_ring failed, resetting engine\n"); \
|
|
+ mach64_dump_engine_info( dev_priv ); \
|
|
+ mach64_do_engine_reset( dev_priv ); \
|
|
+ return ret; \
|
|
+ } \
|
|
+ } \
|
|
+ dev_priv->ring.space -= (n) * sizeof(u32); \
|
|
+ _ring = (u32 *) dev_priv->ring.start; \
|
|
+ _ring_tail = _ring_write = dev_priv->ring.tail; \
|
|
+ _ring_mask = dev_priv->ring.tail_mask; \
|
|
+ } while (0)
|
|
+
|
|
+#define OUT_RING( x ) \
|
|
+do { \
|
|
+ if (MACH64_VERBOSE) { \
|
|
+ DRM_INFO( " OUT_RING( 0x%08x ) at 0x%x\n", \
|
|
+ (unsigned int)(x), _ring_write ); \
|
|
+ } \
|
|
+ _ring[_ring_write++] = cpu_to_le32( x ); \
|
|
+ _ring_write &= _ring_mask; \
|
|
+} while (0)
|
|
+
|
|
+#define ADVANCE_RING() \
|
|
+do { \
|
|
+ if (MACH64_VERBOSE) { \
|
|
+ DRM_INFO( "ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \
|
|
+ _ring_write, _ring_tail ); \
|
|
+ } \
|
|
+ DRM_MEMORYBARRIER(); \
|
|
+ mach64_clear_dma_eol( &_ring[(_ring_tail - 2) & _ring_mask] ); \
|
|
+ DRM_MEMORYBARRIER(); \
|
|
+ dev_priv->ring.tail = _ring_write; \
|
|
+ mach64_ring_tick( dev_priv, &(dev_priv)->ring ); \
|
|
+} while (0)
|
|
+
|
|
+/**
|
|
+ * Queue a DMA buffer of registers writes into the ring buffer.
|
|
+ */
|
|
+int mach64_add_buf_to_ring(drm_mach64_private_t *dev_priv,
|
|
+ drm_mach64_freelist_t *entry)
|
|
+{
|
|
+ int bytes, pages, remainder;
|
|
+ u32 address, page;
|
|
+ int i;
|
|
+ struct drm_buf *buf = entry->buf;
|
|
+ RING_LOCALS;
|
|
+
|
|
+ bytes = buf->used;
|
|
+ address = GETBUFADDR( buf );
|
|
+ pages = (bytes + MACH64_DMA_CHUNKSIZE - 1) / MACH64_DMA_CHUNKSIZE;
|
|
+
|
|
+ BEGIN_RING( pages * 4 );
|
|
+
|
|
+ for ( i = 0 ; i < pages-1 ; i++ ) {
|
|
+ page = address + i * MACH64_DMA_CHUNKSIZE;
|
|
+ OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_ADDR );
|
|
+ OUT_RING( page );
|
|
+ OUT_RING( MACH64_DMA_CHUNKSIZE | MACH64_DMA_HOLD_OFFSET );
|
|
+ OUT_RING( 0 );
|
|
+ }
|
|
+
|
|
+ /* generate the final descriptor for any remaining commands in this buffer */
|
|
+ page = address + i * MACH64_DMA_CHUNKSIZE;
|
|
+ remainder = bytes - i * MACH64_DMA_CHUNKSIZE;
|
|
+
|
|
+ /* Save dword offset of last descriptor for this buffer.
|
|
+ * This is needed to check for completion of the buffer in freelist_get
|
|
+ */
|
|
+ entry->ring_ofs = RING_WRITE_OFS;
|
|
+
|
|
+ OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_ADDR );
|
|
+ OUT_RING( page );
|
|
+ OUT_RING( remainder | MACH64_DMA_HOLD_OFFSET | MACH64_DMA_EOL );
|
|
+ OUT_RING( 0 );
|
|
+
|
|
+ ADVANCE_RING();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Queue DMA buffer controlling host data tranfers (e.g., blit).
|
|
+ *
|
|
+ * Almost identical to mach64_add_buf_to_ring.
|
|
+ */
|
|
+int mach64_add_hostdata_buf_to_ring(drm_mach64_private_t *dev_priv,
|
|
+ drm_mach64_freelist_t *entry)
|
|
+{
|
|
+ int bytes, pages, remainder;
|
|
+ u32 address, page;
|
|
+ int i;
|
|
+ struct drm_buf *buf = entry->buf;
|
|
+ RING_LOCALS;
|
|
+
|
|
+ bytes = buf->used - MACH64_HOSTDATA_BLIT_OFFSET;
|
|
+ pages = (bytes + MACH64_DMA_CHUNKSIZE - 1) / MACH64_DMA_CHUNKSIZE;
|
|
+ address = GETBUFADDR( buf );
|
|
+
|
|
+ BEGIN_RING( 4 + pages * 4 );
|
|
+
|
|
+ OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_ADDR );
|
|
+ OUT_RING( address );
|
|
+ OUT_RING( MACH64_HOSTDATA_BLIT_OFFSET | MACH64_DMA_HOLD_OFFSET );
|
|
+ OUT_RING( 0 );
|
|
+ address += MACH64_HOSTDATA_BLIT_OFFSET;
|
|
+
|
|
+ for ( i = 0 ; i < pages-1 ; i++ ) {
|
|
+ page = address + i * MACH64_DMA_CHUNKSIZE;
|
|
+ OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_HOSTDATA );
|
|
+ OUT_RING( page );
|
|
+ OUT_RING( MACH64_DMA_CHUNKSIZE | MACH64_DMA_HOLD_OFFSET );
|
|
+ OUT_RING( 0 );
|
|
+ }
|
|
+
|
|
+ /* generate the final descriptor for any remaining commands in this buffer */
|
|
+ page = address + i * MACH64_DMA_CHUNKSIZE;
|
|
+ remainder = bytes - i * MACH64_DMA_CHUNKSIZE;
|
|
+
|
|
+ /* Save dword offset of last descriptor for this buffer.
|
|
+ * This is needed to check for completion of the buffer in freelist_get
|
|
+ */
|
|
+ entry->ring_ofs = RING_WRITE_OFS;
|
|
+
|
|
+ OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_HOSTDATA );
|
|
+ OUT_RING( page );
|
|
+ OUT_RING( remainder | MACH64_DMA_HOLD_OFFSET | MACH64_DMA_EOL );
|
|
+ OUT_RING( 0 );
|
|
+
|
|
+ ADVANCE_RING();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*@}*/
|
|
+
|
|
+
|
|
+/*******************************************************************/
|
|
+/** \name DMA test and initialization */
|
|
+/*@{*/
|
|
+
|
|
+/**
|
|
+ * Perform a simple DMA operation using the pattern registers to test whether
|
|
+ * DMA works.
|
|
+ *
|
|
+ * \return zero if successful.
|
|
+ *
|
|
+ * \note This function was the testbed for many experiences regarding Mach64
|
|
+ * DMA operation. It is left here since it so tricky to get DMA operating
|
|
+ * properly in some architectures and hardware.
|
|
+ */
|
|
+static int mach64_bm_dma_test(struct drm_device * dev)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+ drm_dma_handle_t *cpu_addr_dmah;
|
|
+ u32 data_addr;
|
|
+ u32 *table, *data;
|
|
+ u32 expected[2];
|
|
+ u32 src_cntl, pat_reg0, pat_reg1;
|
|
+ int i, count, failed;
|
|
+
|
|
+ DRM_DEBUG("\n");
|
|
+
|
|
+ table = (u32 *) dev_priv->ring.start;
|
|
+
|
|
+ /* FIXME: get a dma buffer from the freelist here */
|
|
+ DRM_DEBUG("Allocating data memory ...\n");
|
|
+#ifdef __FreeBSD__
|
|
+ DRM_UNLOCK();
|
|
+#endif
|
|
+ cpu_addr_dmah =
|
|
+ drm_pci_alloc(dev, 0x1000, 0x1000, 0xfffffffful);
|
|
+#ifdef __FreeBSD__
|
|
+ DRM_LOCK();
|
|
+#endif
|
|
+ if (!cpu_addr_dmah) {
|
|
+ DRM_INFO("data-memory allocation failed!\n");
|
|
+ return -ENOMEM;
|
|
+ } else {
|
|
+ data = (u32 *) cpu_addr_dmah->vaddr;
|
|
+ data_addr = (u32) cpu_addr_dmah->busaddr;
|
|
+ }
|
|
+
|
|
+ /* Save the X server's value for SRC_CNTL and restore it
|
|
+ * in case our test fails. This prevents the X server
|
|
+ * from disabling it's cache for this register
|
|
+ */
|
|
+ src_cntl = MACH64_READ(MACH64_SRC_CNTL);
|
|
+ pat_reg0 = MACH64_READ(MACH64_PAT_REG0);
|
|
+ pat_reg1 = MACH64_READ(MACH64_PAT_REG1);
|
|
+
|
|
+ mach64_do_wait_for_fifo(dev_priv, 3);
|
|
+
|
|
+ MACH64_WRITE(MACH64_SRC_CNTL, 0);
|
|
+ MACH64_WRITE(MACH64_PAT_REG0, 0x11111111);
|
|
+ MACH64_WRITE(MACH64_PAT_REG1, 0x11111111);
|
|
+
|
|
+ mach64_do_wait_for_idle(dev_priv);
|
|
+
|
|
+ for (i = 0; i < 2; i++) {
|
|
+ u32 reg;
|
|
+ reg = MACH64_READ((MACH64_PAT_REG0 + i * 4));
|
|
+ DRM_DEBUG("(Before DMA Transfer) reg %d = 0x%08x\n", i, reg);
|
|
+ if (reg != 0x11111111) {
|
|
+ DRM_INFO("Error initializing test registers\n");
|
|
+ DRM_INFO("resetting engine ...\n");
|
|
+ mach64_do_engine_reset(dev_priv);
|
|
+ DRM_INFO("freeing data buffer memory.\n");
|
|
+ drm_pci_free(dev, cpu_addr_dmah);
|
|
+ return -EIO;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* fill up a buffer with sets of 2 consecutive writes starting with PAT_REG0 */
|
|
+ count = 0;
|
|
+
|
|
+ data[count++] = cpu_to_le32(DMAREG(MACH64_PAT_REG0) | (1 << 16));
|
|
+ data[count++] = expected[0] = 0x22222222;
|
|
+ data[count++] = expected[1] = 0xaaaaaaaa;
|
|
+
|
|
+ while (count < 1020) {
|
|
+ data[count++] =
|
|
+ cpu_to_le32(DMAREG(MACH64_PAT_REG0) | (1 << 16));
|
|
+ data[count++] = 0x22222222;
|
|
+ data[count++] = 0xaaaaaaaa;
|
|
+ }
|
|
+ data[count++] = cpu_to_le32(DMAREG(MACH64_SRC_CNTL) | (0 << 16));
|
|
+ data[count++] = 0;
|
|
+
|
|
+ DRM_DEBUG("Preparing table ...\n");
|
|
+ table[MACH64_DMA_FRAME_BUF_OFFSET] = cpu_to_le32(MACH64_BM_ADDR +
|
|
+ MACH64_APERTURE_OFFSET);
|
|
+ table[MACH64_DMA_SYS_MEM_ADDR] = cpu_to_le32(data_addr);
|
|
+ table[MACH64_DMA_COMMAND] = cpu_to_le32(count * sizeof(u32)
|
|
+ | MACH64_DMA_HOLD_OFFSET
|
|
+ | MACH64_DMA_EOL);
|
|
+ table[MACH64_DMA_RESERVED] = 0;
|
|
+
|
|
+ DRM_DEBUG("table[0] = 0x%08x\n", table[0]);
|
|
+ DRM_DEBUG("table[1] = 0x%08x\n", table[1]);
|
|
+ DRM_DEBUG("table[2] = 0x%08x\n", table[2]);
|
|
+ DRM_DEBUG("table[3] = 0x%08x\n", table[3]);
|
|
+
|
|
+ for (i = 0; i < 6; i++) {
|
|
+ DRM_DEBUG(" data[%d] = 0x%08x\n", i, data[i]);
|
|
+ }
|
|
+ DRM_DEBUG(" ...\n");
|
|
+ for (i = count - 5; i < count; i++) {
|
|
+ DRM_DEBUG(" data[%d] = 0x%08x\n", i, data[i]);
|
|
+ }
|
|
+
|
|
+ DRM_MEMORYBARRIER();
|
|
+
|
|
+ DRM_DEBUG("waiting for idle...\n");
|
|
+ if ((i = mach64_do_wait_for_idle(dev_priv))) {
|
|
+ DRM_INFO("mach64_do_wait_for_idle failed (result=%d)\n", i);
|
|
+ DRM_INFO("resetting engine ...\n");
|
|
+ mach64_do_engine_reset(dev_priv);
|
|
+ mach64_do_wait_for_fifo(dev_priv, 3);
|
|
+ MACH64_WRITE(MACH64_SRC_CNTL, src_cntl);
|
|
+ MACH64_WRITE(MACH64_PAT_REG0, pat_reg0);
|
|
+ MACH64_WRITE(MACH64_PAT_REG1, pat_reg1);
|
|
+ DRM_INFO("freeing data buffer memory.\n");
|
|
+ drm_pci_free(dev, cpu_addr_dmah);
|
|
+ return i;
|
|
+ }
|
|
+ DRM_DEBUG("waiting for idle...done\n");
|
|
+
|
|
+ DRM_DEBUG("BUS_CNTL = 0x%08x\n", MACH64_READ(MACH64_BUS_CNTL));
|
|
+ DRM_DEBUG("SRC_CNTL = 0x%08x\n", MACH64_READ(MACH64_SRC_CNTL));
|
|
+ DRM_DEBUG("\n");
|
|
+ DRM_DEBUG("data bus addr = 0x%08x\n", data_addr);
|
|
+ DRM_DEBUG("table bus addr = 0x%08x\n", dev_priv->ring.start_addr);
|
|
+
|
|
+ DRM_DEBUG("starting DMA transfer...\n");
|
|
+ MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD,
|
|
+ dev_priv->ring.start_addr | MACH64_CIRCULAR_BUF_SIZE_16KB);
|
|
+
|
|
+ MACH64_WRITE(MACH64_SRC_CNTL,
|
|
+ MACH64_SRC_BM_ENABLE | MACH64_SRC_BM_SYNC |
|
|
+ MACH64_SRC_BM_OP_SYSTEM_TO_REG);
|
|
+
|
|
+ /* Kick off the transfer */
|
|
+ DRM_DEBUG("starting DMA transfer... done.\n");
|
|
+ MACH64_WRITE(MACH64_DST_HEIGHT_WIDTH, 0);
|
|
+
|
|
+ DRM_DEBUG("waiting for idle...\n");
|
|
+
|
|
+ if ((i = mach64_do_wait_for_idle(dev_priv))) {
|
|
+ /* engine locked up, dump register state and reset */
|
|
+ DRM_INFO("mach64_do_wait_for_idle failed (result=%d)\n", i);
|
|
+ mach64_dump_engine_info(dev_priv);
|
|
+ DRM_INFO("resetting engine ...\n");
|
|
+ mach64_do_engine_reset(dev_priv);
|
|
+ mach64_do_wait_for_fifo(dev_priv, 3);
|
|
+ MACH64_WRITE(MACH64_SRC_CNTL, src_cntl);
|
|
+ MACH64_WRITE(MACH64_PAT_REG0, pat_reg0);
|
|
+ MACH64_WRITE(MACH64_PAT_REG1, pat_reg1);
|
|
+ DRM_INFO("freeing data buffer memory.\n");
|
|
+ drm_pci_free(dev, cpu_addr_dmah);
|
|
+ return i;
|
|
+ }
|
|
+
|
|
+ DRM_DEBUG("waiting for idle...done\n");
|
|
+
|
|
+ /* restore SRC_CNTL */
|
|
+ mach64_do_wait_for_fifo(dev_priv, 1);
|
|
+ MACH64_WRITE(MACH64_SRC_CNTL, src_cntl);
|
|
+
|
|
+ failed = 0;
|
|
+
|
|
+ /* Check register values to see if the GUI master operation succeeded */
|
|
+ for (i = 0; i < 2; i++) {
|
|
+ u32 reg;
|
|
+ reg = MACH64_READ((MACH64_PAT_REG0 + i * 4));
|
|
+ DRM_DEBUG("(After DMA Transfer) reg %d = 0x%08x\n", i, reg);
|
|
+ if (reg != expected[i]) {
|
|
+ failed = -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* restore pattern registers */
|
|
+ mach64_do_wait_for_fifo(dev_priv, 2);
|
|
+ MACH64_WRITE(MACH64_PAT_REG0, pat_reg0);
|
|
+ MACH64_WRITE(MACH64_PAT_REG1, pat_reg1);
|
|
+
|
|
+ DRM_DEBUG("freeing data buffer memory.\n");
|
|
+ drm_pci_free(dev, cpu_addr_dmah);
|
|
+ DRM_DEBUG("returning ...\n");
|
|
+
|
|
+ return failed;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Called during the DMA initialization ioctl to initialize all the necessary
|
|
+ * software and hardware state for DMA operation.
|
|
+ */
|
|
+static int mach64_do_dma_init(struct drm_device * dev, drm_mach64_init_t * init)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv;
|
|
+ u32 tmp;
|
|
+ int i, ret;
|
|
+
|
|
+ DRM_DEBUG("\n");
|
|
+
|
|
+ dev_priv = drm_alloc(sizeof(drm_mach64_private_t), DRM_MEM_DRIVER);
|
|
+ if (dev_priv == NULL)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ memset(dev_priv, 0, sizeof(drm_mach64_private_t));
|
|
+
|
|
+ dev_priv->is_pci = init->is_pci;
|
|
+
|
|
+ dev_priv->fb_bpp = init->fb_bpp;
|
|
+ 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;
|
|
+
|
|
+ dev_priv->depth_bpp = init->depth_bpp;
|
|
+ dev_priv->depth_offset = init->depth_offset;
|
|
+ dev_priv->depth_pitch = init->depth_pitch;
|
|
+
|
|
+ dev_priv->front_offset_pitch = (((dev_priv->front_pitch / 8) << 22) |
|
|
+ (dev_priv->front_offset >> 3));
|
|
+ dev_priv->back_offset_pitch = (((dev_priv->back_pitch / 8) << 22) |
|
|
+ (dev_priv->back_offset >> 3));
|
|
+ dev_priv->depth_offset_pitch = (((dev_priv->depth_pitch / 8) << 22) |
|
|
+ (dev_priv->depth_offset >> 3));
|
|
+
|
|
+ dev_priv->usec_timeout = 1000000;
|
|
+
|
|
+ /* Set up the freelist, placeholder list and pending list */
|
|
+ INIT_LIST_HEAD(&dev_priv->free_list);
|
|
+ INIT_LIST_HEAD(&dev_priv->placeholders);
|
|
+ INIT_LIST_HEAD(&dev_priv->pending);
|
|
+
|
|
+ dev_priv->sarea = drm_getsarea(dev);
|
|
+ if (!dev_priv->sarea) {
|
|
+ DRM_ERROR("can not find sarea!\n");
|
|
+ dev->dev_private = (void *)dev_priv;
|
|
+ mach64_do_cleanup_dma(dev);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ dev_priv->fb = drm_core_findmap(dev, init->fb_offset);
|
|
+ if (!dev_priv->fb) {
|
|
+ DRM_ERROR("can not find frame buffer map!\n");
|
|
+ dev->dev_private = (void *)dev_priv;
|
|
+ mach64_do_cleanup_dma(dev);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
|
|
+ if (!dev_priv->mmio) {
|
|
+ DRM_ERROR("can not find mmio map!\n");
|
|
+ dev->dev_private = (void *)dev_priv;
|
|
+ mach64_do_cleanup_dma(dev);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ dev_priv->ring_map = drm_core_findmap(dev, init->ring_offset);
|
|
+ if (!dev_priv->ring_map) {
|
|
+ DRM_ERROR("can not find ring map!\n");
|
|
+ dev->dev_private = (void *)dev_priv;
|
|
+ mach64_do_cleanup_dma(dev);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ dev_priv->sarea_priv = (drm_mach64_sarea_t *)
|
|
+ ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset);
|
|
+
|
|
+ if (!dev_priv->is_pci) {
|
|
+ drm_core_ioremap(dev_priv->ring_map, dev);
|
|
+ if (!dev_priv->ring_map->handle) {
|
|
+ DRM_ERROR("can not ioremap virtual address for"
|
|
+ " descriptor ring\n");
|
|
+ dev->dev_private = (void *)dev_priv;
|
|
+ mach64_do_cleanup_dma(dev);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ dev->agp_buffer_token = init->buffers_offset;
|
|
+ dev->agp_buffer_map =
|
|
+ drm_core_findmap(dev, init->buffers_offset);
|
|
+ if (!dev->agp_buffer_map) {
|
|
+ DRM_ERROR("can not find dma buffer map!\n");
|
|
+ dev->dev_private = (void *)dev_priv;
|
|
+ mach64_do_cleanup_dma(dev);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ /* there might be a nicer way to do this -
|
|
+ dev isn't passed all the way though the mach64 - DA */
|
|
+ dev_priv->dev_buffers = dev->agp_buffer_map;
|
|
+
|
|
+ drm_core_ioremap(dev->agp_buffer_map, dev);
|
|
+ if (!dev->agp_buffer_map->handle) {
|
|
+ DRM_ERROR("can not ioremap virtual address for"
|
|
+ " dma buffer\n");
|
|
+ dev->dev_private = (void *)dev_priv;
|
|
+ mach64_do_cleanup_dma(dev);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ dev_priv->agp_textures =
|
|
+ drm_core_findmap(dev, init->agp_textures_offset);
|
|
+ if (!dev_priv->agp_textures) {
|
|
+ DRM_ERROR("can not find agp texture region!\n");
|
|
+ dev->dev_private = (void *)dev_priv;
|
|
+ mach64_do_cleanup_dma(dev);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ dev->dev_private = (void *)dev_priv;
|
|
+
|
|
+ dev_priv->driver_mode = init->dma_mode;
|
|
+
|
|
+ /* changing the FIFO size from the default causes problems with DMA */
|
|
+ tmp = MACH64_READ(MACH64_GUI_CNTL);
|
|
+ if ((tmp & MACH64_CMDFIFO_SIZE_MASK) != MACH64_CMDFIFO_SIZE_128) {
|
|
+ DRM_INFO("Setting FIFO size to 128 entries\n");
|
|
+ /* FIFO must be empty to change the FIFO depth */
|
|
+ if ((ret = mach64_do_wait_for_idle(dev_priv))) {
|
|
+ DRM_ERROR
|
|
+ ("wait for idle failed before changing FIFO depth!\n");
|
|
+ mach64_do_cleanup_dma(dev);
|
|
+ return ret;
|
|
+ }
|
|
+ MACH64_WRITE(MACH64_GUI_CNTL, ((tmp & ~MACH64_CMDFIFO_SIZE_MASK)
|
|
+ | MACH64_CMDFIFO_SIZE_128));
|
|
+ /* need to read GUI_STAT for proper sync according to docs */
|
|
+ if ((ret = mach64_do_wait_for_idle(dev_priv))) {
|
|
+ DRM_ERROR
|
|
+ ("wait for idle failed when changing FIFO depth!\n");
|
|
+ mach64_do_cleanup_dma(dev);
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ dev_priv->ring.size = 0x4000; /* 16KB */
|
|
+ dev_priv->ring.start = dev_priv->ring_map->handle;
|
|
+ dev_priv->ring.start_addr = (u32) dev_priv->ring_map->offset;
|
|
+
|
|
+ memset(dev_priv->ring.start, 0, dev_priv->ring.size);
|
|
+ DRM_INFO("descriptor ring: cpu addr %p, bus addr: 0x%08x\n",
|
|
+ dev_priv->ring.start, dev_priv->ring.start_addr);
|
|
+
|
|
+ ret = 0;
|
|
+ if (dev_priv->driver_mode != MACH64_MODE_MMIO) {
|
|
+
|
|
+ /* enable block 1 registers and bus mastering */
|
|
+ MACH64_WRITE(MACH64_BUS_CNTL, ((MACH64_READ(MACH64_BUS_CNTL)
|
|
+ | MACH64_BUS_EXT_REG_EN)
|
|
+ & ~MACH64_BUS_MASTER_DIS));
|
|
+
|
|
+ /* try a DMA GUI-mastering pass and fall back to MMIO if it fails */
|
|
+ DRM_DEBUG("Starting DMA test...\n");
|
|
+ if ((ret = mach64_bm_dma_test(dev))) {
|
|
+ dev_priv->driver_mode = MACH64_MODE_MMIO;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ switch (dev_priv->driver_mode) {
|
|
+ case MACH64_MODE_MMIO:
|
|
+ MACH64_WRITE(MACH64_BUS_CNTL, (MACH64_READ(MACH64_BUS_CNTL)
|
|
+ | MACH64_BUS_EXT_REG_EN
|
|
+ | MACH64_BUS_MASTER_DIS));
|
|
+ if (init->dma_mode == MACH64_MODE_MMIO)
|
|
+ DRM_INFO("Forcing pseudo-DMA mode\n");
|
|
+ else
|
|
+ DRM_INFO
|
|
+ ("DMA test failed (ret=%d), using pseudo-DMA mode\n",
|
|
+ ret);
|
|
+ break;
|
|
+ case MACH64_MODE_DMA_SYNC:
|
|
+ DRM_INFO("DMA test succeeded, using synchronous DMA mode\n");
|
|
+ break;
|
|
+ case MACH64_MODE_DMA_ASYNC:
|
|
+ default:
|
|
+ DRM_INFO("DMA test succeeded, using asynchronous DMA mode\n");
|
|
+ }
|
|
+
|
|
+ dev_priv->ring_running = 0;
|
|
+
|
|
+ /* setup offsets for physical address of table start and end */
|
|
+ dev_priv->ring.head_addr = dev_priv->ring.start_addr;
|
|
+ dev_priv->ring.head = dev_priv->ring.tail = 0;
|
|
+ dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;
|
|
+ dev_priv->ring.space = dev_priv->ring.size;
|
|
+
|
|
+ /* setup physical address and size of descriptor table */
|
|
+ mach64_do_wait_for_fifo(dev_priv, 1);
|
|
+ MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD,
|
|
+ (dev_priv->ring.
|
|
+ head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB));
|
|
+
|
|
+ /* init frame counter */
|
|
+ dev_priv->sarea_priv->frames_queued = 0;
|
|
+ for (i = 0; i < MACH64_MAX_QUEUED_FRAMES; i++) {
|
|
+ dev_priv->frame_ofs[i] = ~0; /* All ones indicates placeholder */
|
|
+ }
|
|
+
|
|
+ /* Allocate the DMA buffer freelist */
|
|
+ if ((ret = mach64_init_freelist(dev))) {
|
|
+ DRM_ERROR("Freelist allocation failed\n");
|
|
+ mach64_do_cleanup_dma(dev);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*******************************************************************/
|
|
+/** MMIO Pseudo-DMA (intended primarily for debugging, not performance)
|
|
+ */
|
|
+
|
|
+int mach64_do_dispatch_pseudo_dma(drm_mach64_private_t *dev_priv)
|
|
+{
|
|
+ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
|
|
+ volatile u32 *ring_read;
|
|
+ struct list_head *ptr;
|
|
+ drm_mach64_freelist_t *entry;
|
|
+ struct drm_buf *buf = NULL;
|
|
+ u32 *buf_ptr;
|
|
+ u32 used, reg, target;
|
|
+ int fifo, count, found, ret, no_idle_wait;
|
|
+
|
|
+ fifo = count = reg = no_idle_wait = 0;
|
|
+ target = MACH64_BM_ADDR;
|
|
+
|
|
+ if ((ret = mach64_do_wait_for_idle(dev_priv)) < 0) {
|
|
+ DRM_INFO("idle failed before pseudo-dma dispatch, resetting engine\n");
|
|
+ mach64_dump_engine_info(dev_priv);
|
|
+ mach64_do_engine_reset(dev_priv);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ring_read = (u32 *) ring->start;
|
|
+
|
|
+ while (ring->tail != ring->head) {
|
|
+ u32 buf_addr, new_target, offset;
|
|
+ u32 bytes, remaining, head, eol;
|
|
+
|
|
+ head = ring->head;
|
|
+
|
|
+ new_target =
|
|
+ le32_to_cpu(ring_read[head++]) - MACH64_APERTURE_OFFSET;
|
|
+ buf_addr = le32_to_cpu(ring_read[head++]);
|
|
+ eol = le32_to_cpu(ring_read[head]) & MACH64_DMA_EOL;
|
|
+ bytes = le32_to_cpu(ring_read[head++])
|
|
+ & ~(MACH64_DMA_HOLD_OFFSET | MACH64_DMA_EOL);
|
|
+ head++;
|
|
+ head &= ring->tail_mask;
|
|
+
|
|
+ /* can't wait for idle between a blit setup descriptor
|
|
+ * and a HOSTDATA descriptor or the engine will lock
|
|
+ */
|
|
+ if (new_target == MACH64_BM_HOSTDATA
|
|
+ && target == MACH64_BM_ADDR)
|
|
+ no_idle_wait = 1;
|
|
+
|
|
+ target = new_target;
|
|
+
|
|
+ found = 0;
|
|
+ offset = 0;
|
|
+ list_for_each(ptr, &dev_priv->pending) {
|
|
+ entry = list_entry(ptr, drm_mach64_freelist_t, list);
|
|
+ buf = entry->buf;
|
|
+ offset = buf_addr - GETBUFADDR(buf);
|
|
+ if (offset >= 0 && offset < MACH64_BUFFER_SIZE) {
|
|
+ found = 1;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!found || buf == NULL) {
|
|
+ DRM_ERROR
|
|
+ ("Couldn't find pending buffer: head: %u tail: %u buf_addr: 0x%08x %s\n",
|
|
+ head, ring->tail, buf_addr, (eol ? "eol" : ""));
|
|
+ mach64_dump_ring_info(dev_priv);
|
|
+ mach64_do_engine_reset(dev_priv);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* Hand feed the buffer to the card via MMIO, waiting for the fifo
|
|
+ * every 16 writes
|
|
+ */
|
|
+ DRM_DEBUG("target: (0x%08x) %s\n", target,
|
|
+ (target ==
|
|
+ MACH64_BM_HOSTDATA ? "BM_HOSTDATA" : "BM_ADDR"));
|
|
+ DRM_DEBUG("offset: %u bytes: %u used: %u\n", offset, bytes,
|
|
+ buf->used);
|
|
+
|
|
+ remaining = (buf->used - offset) >> 2; /* dwords remaining in buffer */
|
|
+ used = bytes >> 2; /* dwords in buffer for this descriptor */
|
|
+ buf_ptr = (u32 *) ((char *)GETBUFPTR(buf) + offset);
|
|
+
|
|
+ while (used) {
|
|
+
|
|
+ if (count == 0) {
|
|
+ if (target == MACH64_BM_HOSTDATA) {
|
|
+ reg = DMAREG(MACH64_HOST_DATA0);
|
|
+ count =
|
|
+ (remaining > 16) ? 16 : remaining;
|
|
+ fifo = 0;
|
|
+ } else {
|
|
+ reg = le32_to_cpu(*buf_ptr++);
|
|
+ used--;
|
|
+ count = (reg >> 16) + 1;
|
|
+ }
|
|
+
|
|
+ reg = reg & 0xffff;
|
|
+ reg = MMSELECT(reg);
|
|
+ }
|
|
+ while (count && used) {
|
|
+ if (!fifo) {
|
|
+ if (no_idle_wait) {
|
|
+ if ((ret =
|
|
+ mach64_do_wait_for_fifo
|
|
+ (dev_priv, 16)) < 0) {
|
|
+ no_idle_wait = 0;
|
|
+ return ret;
|
|
+ }
|
|
+ } else {
|
|
+ if ((ret =
|
|
+ mach64_do_wait_for_idle
|
|
+ (dev_priv)) < 0) {
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+ fifo = 16;
|
|
+ }
|
|
+ --fifo;
|
|
+ MACH64_WRITE(reg, le32_to_cpu(*buf_ptr++));
|
|
+ used--;
|
|
+ remaining--;
|
|
+
|
|
+ reg += 4;
|
|
+ count--;
|
|
+ }
|
|
+ }
|
|
+ ring->head = head;
|
|
+ ring->head_addr = ring->start_addr + (ring->head * sizeof(u32));
|
|
+ ring->space += (4 * sizeof(u32));
|
|
+ }
|
|
+
|
|
+ if ((ret = mach64_do_wait_for_idle(dev_priv)) < 0) {
|
|
+ return ret;
|
|
+ }
|
|
+ MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD,
|
|
+ ring->head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB);
|
|
+
|
|
+ DRM_DEBUG("completed\n");
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*@}*/
|
|
+
|
|
+
|
|
+/*******************************************************************/
|
|
+/** \name DMA cleanup */
|
|
+/*@{*/
|
|
+
|
|
+int mach64_do_cleanup_dma(struct drm_device * dev)
|
|
+{
|
|
+ DRM_DEBUG("\n");
|
|
+
|
|
+ /* 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)
|
|
+ drm_irq_uninstall(dev);
|
|
+
|
|
+ if (dev->dev_private) {
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+
|
|
+ if (!dev_priv->is_pci) {
|
|
+ if (dev_priv->ring_map)
|
|
+ drm_core_ioremapfree(dev_priv->ring_map, dev);
|
|
+
|
|
+ if (dev->agp_buffer_map) {
|
|
+ drm_core_ioremapfree(dev->agp_buffer_map, dev);
|
|
+ dev->agp_buffer_map = NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ mach64_destroy_freelist(dev);
|
|
+
|
|
+ drm_free(dev_priv, sizeof(drm_mach64_private_t),
|
|
+ DRM_MEM_DRIVER);
|
|
+ dev->dev_private = NULL;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*@}*/
|
|
+
|
|
+
|
|
+/*******************************************************************/
|
|
+/** \name IOCTL handlers */
|
|
+/*@{*/
|
|
+
|
|
+int mach64_dma_init(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv)
|
|
+{
|
|
+ drm_mach64_init_t *init = data;
|
|
+
|
|
+ DRM_DEBUG("\n");
|
|
+
|
|
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
|
|
+
|
|
+ switch (init->func) {
|
|
+ case DRM_MACH64_INIT_DMA:
|
|
+ return mach64_do_dma_init(dev, init);
|
|
+ case DRM_MACH64_CLEANUP_DMA:
|
|
+ return mach64_do_cleanup_dma(dev);
|
|
+ }
|
|
+
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
+int mach64_dma_idle(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+
|
|
+ DRM_DEBUG("\n");
|
|
+
|
|
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
|
|
+
|
|
+ return mach64_do_dma_idle(dev_priv);
|
|
+}
|
|
+
|
|
+int mach64_dma_flush(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+
|
|
+ DRM_DEBUG("\n");
|
|
+
|
|
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
|
|
+
|
|
+ return mach64_do_dma_flush(dev_priv);
|
|
+}
|
|
+
|
|
+int mach64_engine_reset(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+
|
|
+ DRM_DEBUG("\n");
|
|
+
|
|
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
|
|
+
|
|
+ return mach64_do_engine_reset(dev_priv);
|
|
+}
|
|
+
|
|
+/*@}*/
|
|
+
|
|
+
|
|
+/*******************************************************************/
|
|
+/** \name Freelist management */
|
|
+/*@{*/
|
|
+
|
|
+int mach64_init_freelist(struct drm_device * dev)
|
|
+{
|
|
+ struct drm_device_dma *dma = dev->dma;
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+ drm_mach64_freelist_t *entry;
|
|
+ struct list_head *ptr;
|
|
+ int i;
|
|
+
|
|
+ DRM_DEBUG("adding %d buffers to freelist\n", dma->buf_count);
|
|
+
|
|
+ for (i = 0; i < dma->buf_count; i++) {
|
|
+ if ((entry =
|
|
+ (drm_mach64_freelist_t *)
|
|
+ drm_alloc(sizeof(drm_mach64_freelist_t),
|
|
+ DRM_MEM_BUFLISTS)) == NULL)
|
|
+ return -ENOMEM;
|
|
+ memset(entry, 0, sizeof(drm_mach64_freelist_t));
|
|
+ entry->buf = dma->buflist[i];
|
|
+ ptr = &entry->list;
|
|
+ list_add_tail(ptr, &dev_priv->free_list);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void mach64_destroy_freelist(struct drm_device * dev)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+ drm_mach64_freelist_t *entry;
|
|
+ struct list_head *ptr;
|
|
+ struct list_head *tmp;
|
|
+
|
|
+ DRM_DEBUG("\n");
|
|
+
|
|
+ list_for_each_safe(ptr, tmp, &dev_priv->pending) {
|
|
+ list_del(ptr);
|
|
+ entry = list_entry(ptr, drm_mach64_freelist_t, list);
|
|
+ drm_free(entry, sizeof(*entry), DRM_MEM_BUFLISTS);
|
|
+ }
|
|
+ list_for_each_safe(ptr, tmp, &dev_priv->placeholders) {
|
|
+ list_del(ptr);
|
|
+ entry = list_entry(ptr, drm_mach64_freelist_t, list);
|
|
+ drm_free(entry, sizeof(*entry), DRM_MEM_BUFLISTS);
|
|
+ }
|
|
+
|
|
+ list_for_each_safe(ptr, tmp, &dev_priv->free_list) {
|
|
+ list_del(ptr);
|
|
+ entry = list_entry(ptr, drm_mach64_freelist_t, list);
|
|
+ drm_free(entry, sizeof(*entry), DRM_MEM_BUFLISTS);
|
|
+ }
|
|
+}
|
|
+
|
|
+/* IMPORTANT: This function should only be called when the engine is idle or locked up,
|
|
+ * as it assumes all buffers in the pending list have been completed by the hardware.
|
|
+ */
|
|
+int mach64_do_release_used_buffers(drm_mach64_private_t *dev_priv)
|
|
+{
|
|
+ struct list_head *ptr;
|
|
+ struct list_head *tmp;
|
|
+ drm_mach64_freelist_t *entry;
|
|
+ int i;
|
|
+
|
|
+ if (list_empty(&dev_priv->pending))
|
|
+ return 0;
|
|
+
|
|
+ /* Iterate the pending list and move all buffers into the freelist... */
|
|
+ i = 0;
|
|
+ list_for_each_safe(ptr, tmp, &dev_priv->pending) {
|
|
+ entry = list_entry(ptr, drm_mach64_freelist_t, list);
|
|
+ if (entry->discard) {
|
|
+ entry->buf->pending = 0;
|
|
+ list_del(ptr);
|
|
+ list_add_tail(ptr, &dev_priv->free_list);
|
|
+ i++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ DRM_DEBUG("released %d buffers from pending list\n", i);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mach64_do_reclaim_completed(drm_mach64_private_t *dev_priv)
|
|
+{
|
|
+ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
|
|
+ struct list_head *ptr;
|
|
+ struct list_head *tmp;
|
|
+ drm_mach64_freelist_t *entry;
|
|
+ u32 head, tail, ofs;
|
|
+
|
|
+ mach64_ring_tick(dev_priv, ring);
|
|
+ head = ring->head;
|
|
+ tail = ring->tail;
|
|
+
|
|
+ if (head == tail) {
|
|
+#if MACH64_EXTRA_CHECKING
|
|
+ if (MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE) {
|
|
+ DRM_ERROR("Empty ring with non-idle engine!\n");
|
|
+ mach64_dump_ring_info(dev_priv);
|
|
+ return -1;
|
|
+ }
|
|
+#endif
|
|
+ /* last pass is complete, so release everything */
|
|
+ mach64_do_release_used_buffers(dev_priv);
|
|
+ DRM_DEBUG("idle engine, freed all buffers.\n");
|
|
+ if (list_empty(&dev_priv->free_list)) {
|
|
+ DRM_ERROR("Freelist empty with idle engine\n");
|
|
+ return -1;
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+ /* Look for a completed buffer and bail out of the loop
|
|
+ * as soon as we find one -- don't waste time trying
|
|
+ * to free extra bufs here, leave that to do_release_used_buffers
|
|
+ */
|
|
+ list_for_each_safe(ptr, tmp, &dev_priv->pending) {
|
|
+ entry = list_entry(ptr, drm_mach64_freelist_t, list);
|
|
+ ofs = entry->ring_ofs;
|
|
+ if (entry->discard &&
|
|
+ ((head < tail && (ofs < head || ofs >= tail)) ||
|
|
+ (head > tail && (ofs < head && ofs >= tail)))) {
|
|
+#if MACH64_EXTRA_CHECKING
|
|
+ int i;
|
|
+
|
|
+ for (i = head; i != tail; i = (i + 4) & ring->tail_mask)
|
|
+ {
|
|
+ u32 o1 = le32_to_cpu(((u32 *) ring->
|
|
+ start)[i + 1]);
|
|
+ u32 o2 = GETBUFADDR(entry->buf);
|
|
+
|
|
+ if (o1 == o2) {
|
|
+ DRM_ERROR
|
|
+ ("Attempting to free used buffer: "
|
|
+ "i=%d buf=0x%08x\n",
|
|
+ i, o1);
|
|
+ mach64_dump_ring_info(dev_priv);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+ /* found a processed buffer */
|
|
+ entry->buf->pending = 0;
|
|
+ list_del(ptr);
|
|
+ list_add_tail(ptr, &dev_priv->free_list);
|
|
+ DRM_DEBUG
|
|
+ ("freed processed buffer (head=%d tail=%d "
|
|
+ "buf ring ofs=%d).\n",
|
|
+ head, tail, ofs);
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+struct drm_buf *mach64_freelist_get(drm_mach64_private_t *dev_priv)
|
|
+{
|
|
+ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
|
|
+ drm_mach64_freelist_t *entry;
|
|
+ struct list_head *ptr;
|
|
+ int t;
|
|
+
|
|
+ if (list_empty(&dev_priv->free_list)) {
|
|
+ if (list_empty(&dev_priv->pending)) {
|
|
+ DRM_ERROR
|
|
+ ("Couldn't get buffer - pending and free lists empty\n");
|
|
+ t = 0;
|
|
+ list_for_each(ptr, &dev_priv->placeholders) {
|
|
+ t++;
|
|
+ }
|
|
+ DRM_INFO("Placeholders: %d\n", t);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ for (t = 0; t < dev_priv->usec_timeout; t++) {
|
|
+ int ret;
|
|
+
|
|
+ ret = mach64_do_reclaim_completed(dev_priv);
|
|
+ if (ret == 0)
|
|
+ goto _freelist_entry_found;
|
|
+ if (ret < 0)
|
|
+ return NULL;
|
|
+
|
|
+ DRM_UDELAY(1);
|
|
+ }
|
|
+ mach64_dump_ring_info(dev_priv);
|
|
+ DRM_ERROR
|
|
+ ("timeout waiting for buffers: ring head_addr: 0x%08x head: %d tail: %d\n",
|
|
+ ring->head_addr, ring->head, ring->tail);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ _freelist_entry_found:
|
|
+ ptr = dev_priv->free_list.next;
|
|
+ list_del(ptr);
|
|
+ entry = list_entry(ptr, drm_mach64_freelist_t, list);
|
|
+ entry->buf->used = 0;
|
|
+ list_add_tail(ptr, &dev_priv->placeholders);
|
|
+ return entry->buf;
|
|
+}
|
|
+
|
|
+int mach64_freelist_put(drm_mach64_private_t *dev_priv, struct drm_buf *copy_buf)
|
|
+{
|
|
+ struct list_head *ptr;
|
|
+ drm_mach64_freelist_t *entry;
|
|
+
|
|
+#if MACH64_EXTRA_CHECKING
|
|
+ list_for_each(ptr, &dev_priv->pending) {
|
|
+ entry = list_entry(ptr, drm_mach64_freelist_t, list);
|
|
+ if (copy_buf == entry->buf) {
|
|
+ DRM_ERROR("Trying to release a pending buf\n");
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+ ptr = dev_priv->placeholders.next;
|
|
+ entry = list_entry(ptr, drm_mach64_freelist_t, list);
|
|
+ copy_buf->pending = 0;
|
|
+ copy_buf->used = 0;
|
|
+ entry->buf = copy_buf;
|
|
+ entry->discard = 1;
|
|
+ list_del(ptr);
|
|
+ list_add_tail(ptr, &dev_priv->free_list);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*@}*/
|
|
+
|
|
+
|
|
+/*******************************************************************/
|
|
+/** \name DMA buffer request and submission IOCTL handler */
|
|
+/*@{*/
|
|
+
|
|
+static int mach64_dma_get_buffers(struct drm_device *dev,
|
|
+ struct drm_file *file_priv,
|
|
+ struct drm_dma * d)
|
|
+{
|
|
+ int i;
|
|
+ struct drm_buf *buf;
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+
|
|
+ for (i = d->granted_count; i < d->request_count; i++) {
|
|
+ buf = mach64_freelist_get(dev_priv);
|
|
+#if MACH64_EXTRA_CHECKING
|
|
+ if (!buf)
|
|
+ return -EFAULT;
|
|
+#else
|
|
+ if (!buf)
|
|
+ return -EAGAIN;
|
|
+#endif
|
|
+
|
|
+ buf->file_priv = file_priv;
|
|
+
|
|
+ if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx,
|
|
+ sizeof(buf->idx)))
|
|
+ return -EFAULT;
|
|
+ if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total,
|
|
+ sizeof(buf->total)))
|
|
+ return -EFAULT;
|
|
+
|
|
+ d->granted_count++;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int mach64_dma_buffers(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv)
|
|
+{
|
|
+ struct drm_device_dma *dma = dev->dma;
|
|
+ struct drm_dma *d = data;
|
|
+ int ret = 0;
|
|
+
|
|
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
|
|
+
|
|
+ /* Please don't send us buffers.
|
|
+ */
|
|
+ if (d->send_count != 0) {
|
|
+ DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
|
|
+ DRM_CURRENTPID, d->send_count);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* 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",
|
|
+ DRM_CURRENTPID, d->request_count, dma->buf_count);
|
|
+ ret = -EINVAL;
|
|
+ }
|
|
+
|
|
+ d->granted_count = 0;
|
|
+
|
|
+ if (d->request_count) {
|
|
+ ret = mach64_dma_get_buffers(dev, file_priv, d);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+void mach64_driver_lastclose(struct drm_device * dev)
|
|
+{
|
|
+ mach64_do_cleanup_dma(dev);
|
|
+}
|
|
+
|
|
+/*@}*/
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/mach64/mach64_drm.h
|
|
@@ -0,0 +1,256 @@
|
|
+/* mach64_drm.h -- Public header for the mach64 driver -*- linux-c -*-
|
|
+ * Created: Thu Nov 30 20:04:32 2000 by gareth@valinux.com
|
|
+ */
|
|
+/*
|
|
+ * Copyright 2000 Gareth Hughes
|
|
+ * Copyright 2002 Frank C. Earl
|
|
+ * Copyright 2002-2003 Leif Delgass
|
|
+ * 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 COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Gareth Hughes <gareth@valinux.com>
|
|
+ * Frank C. Earl <fearl@airmail.net>
|
|
+ * Leif Delgass <ldelgass@retinalburn.net>
|
|
+ */
|
|
+
|
|
+#ifndef __MACH64_DRM_H__
|
|
+#define __MACH64_DRM_H__
|
|
+
|
|
+/* WARNING: If you change any of these defines, make sure to change the
|
|
+ * defines in the Xserver file (mach64_sarea.h)
|
|
+ */
|
|
+#ifndef __MACH64_SAREA_DEFINES__
|
|
+#define __MACH64_SAREA_DEFINES__
|
|
+
|
|
+/* What needs to be changed for the current vertex buffer?
|
|
+ * GH: We're going to be pedantic about this. We want the card to do as
|
|
+ * little as possible, so let's avoid having it fetch a whole bunch of
|
|
+ * register values that don't change all that often, if at all.
|
|
+ */
|
|
+#define MACH64_UPLOAD_DST_OFF_PITCH 0x0001
|
|
+#define MACH64_UPLOAD_Z_OFF_PITCH 0x0002
|
|
+#define MACH64_UPLOAD_Z_ALPHA_CNTL 0x0004
|
|
+#define MACH64_UPLOAD_SCALE_3D_CNTL 0x0008
|
|
+#define MACH64_UPLOAD_DP_FOG_CLR 0x0010
|
|
+#define MACH64_UPLOAD_DP_WRITE_MASK 0x0020
|
|
+#define MACH64_UPLOAD_DP_PIX_WIDTH 0x0040
|
|
+#define MACH64_UPLOAD_SETUP_CNTL 0x0080
|
|
+#define MACH64_UPLOAD_MISC 0x0100
|
|
+#define MACH64_UPLOAD_TEXTURE 0x0200
|
|
+#define MACH64_UPLOAD_TEX0IMAGE 0x0400
|
|
+#define MACH64_UPLOAD_TEX1IMAGE 0x0800
|
|
+#define MACH64_UPLOAD_CLIPRECTS 0x1000 /* handled client-side */
|
|
+#define MACH64_UPLOAD_CONTEXT 0x00ff
|
|
+#define MACH64_UPLOAD_ALL 0x1fff
|
|
+
|
|
+/* DMA buffer size
|
|
+ */
|
|
+#define MACH64_BUFFER_SIZE 16384
|
|
+
|
|
+/* Max number of swaps allowed on the ring
|
|
+ * before the client must wait
|
|
+ */
|
|
+#define MACH64_MAX_QUEUED_FRAMES 3U
|
|
+
|
|
+/* Byte offsets for host blit buffer data
|
|
+ */
|
|
+#define MACH64_HOSTDATA_BLIT_OFFSET 104
|
|
+
|
|
+/* Keep these small for testing.
|
|
+ */
|
|
+#define MACH64_NR_SAREA_CLIPRECTS 8
|
|
+
|
|
+#define MACH64_CARD_HEAP 0
|
|
+#define MACH64_AGP_HEAP 1
|
|
+#define MACH64_NR_TEX_HEAPS 2
|
|
+#define MACH64_NR_TEX_REGIONS 64
|
|
+#define MACH64_LOG_TEX_GRANULARITY 16
|
|
+
|
|
+#define MACH64_TEX_MAXLEVELS 1
|
|
+
|
|
+#define MACH64_NR_CONTEXT_REGS 15
|
|
+#define MACH64_NR_TEXTURE_REGS 4
|
|
+
|
|
+#endif /* __MACH64_SAREA_DEFINES__ */
|
|
+
|
|
+typedef struct {
|
|
+ unsigned int dst_off_pitch;
|
|
+
|
|
+ unsigned int z_off_pitch;
|
|
+ unsigned int z_cntl;
|
|
+ unsigned int alpha_tst_cntl;
|
|
+
|
|
+ unsigned int scale_3d_cntl;
|
|
+
|
|
+ unsigned int sc_left_right;
|
|
+ unsigned int sc_top_bottom;
|
|
+
|
|
+ unsigned int dp_fog_clr;
|
|
+ unsigned int dp_write_mask;
|
|
+ unsigned int dp_pix_width;
|
|
+ unsigned int dp_mix;
|
|
+ unsigned int dp_src;
|
|
+
|
|
+ unsigned int clr_cmp_cntl;
|
|
+ unsigned int gui_traj_cntl;
|
|
+
|
|
+ unsigned int setup_cntl;
|
|
+
|
|
+ unsigned int tex_size_pitch;
|
|
+ unsigned int tex_cntl;
|
|
+ unsigned int secondary_tex_off;
|
|
+ unsigned int tex_offset;
|
|
+} drm_mach64_context_regs_t;
|
|
+
|
|
+typedef struct drm_mach64_sarea {
|
|
+ /* The channel for communication of state information to the kernel
|
|
+ * on firing a vertex dma buffer.
|
|
+ */
|
|
+ drm_mach64_context_regs_t context_state;
|
|
+ unsigned int dirty;
|
|
+ unsigned int vertsize;
|
|
+
|
|
+ /* The current cliprects, or a subset thereof.
|
|
+ */
|
|
+ struct drm_clip_rect boxes[MACH64_NR_SAREA_CLIPRECTS];
|
|
+ unsigned int nbox;
|
|
+
|
|
+ /* Counters for client-side throttling of rendering clients.
|
|
+ */
|
|
+ unsigned int frames_queued;
|
|
+
|
|
+ /* Texture memory LRU.
|
|
+ */
|
|
+ struct drm_tex_region tex_list[MACH64_NR_TEX_HEAPS][MACH64_NR_TEX_REGIONS +
|
|
+ 1];
|
|
+ unsigned int tex_age[MACH64_NR_TEX_HEAPS];
|
|
+ int ctx_owner;
|
|
+} drm_mach64_sarea_t;
|
|
+
|
|
+/* WARNING: If you change any of these defines, make sure to change the
|
|
+ * defines in the Xserver file (mach64_common.h)
|
|
+ */
|
|
+
|
|
+/* Mach64 specific ioctls
|
|
+ * The device specific ioctl range is 0x40 to 0x79.
|
|
+ */
|
|
+
|
|
+#define DRM_MACH64_INIT 0x00
|
|
+#define DRM_MACH64_IDLE 0x01
|
|
+#define DRM_MACH64_RESET 0x02
|
|
+#define DRM_MACH64_SWAP 0x03
|
|
+#define DRM_MACH64_CLEAR 0x04
|
|
+#define DRM_MACH64_VERTEX 0x05
|
|
+#define DRM_MACH64_BLIT 0x06
|
|
+#define DRM_MACH64_FLUSH 0x07
|
|
+#define DRM_MACH64_GETPARAM 0x08
|
|
+
|
|
+#define DRM_IOCTL_MACH64_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_MACH64_INIT, drm_mach64_init_t)
|
|
+#define DRM_IOCTL_MACH64_IDLE DRM_IO( DRM_COMMAND_BASE + DRM_MACH64_IDLE )
|
|
+#define DRM_IOCTL_MACH64_RESET DRM_IO( DRM_COMMAND_BASE + DRM_MACH64_RESET )
|
|
+#define DRM_IOCTL_MACH64_SWAP DRM_IO( DRM_COMMAND_BASE + DRM_MACH64_SWAP )
|
|
+#define DRM_IOCTL_MACH64_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_MACH64_CLEAR, drm_mach64_clear_t)
|
|
+#define DRM_IOCTL_MACH64_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_MACH64_VERTEX, drm_mach64_vertex_t)
|
|
+#define DRM_IOCTL_MACH64_BLIT DRM_IOW( DRM_COMMAND_BASE + DRM_MACH64_BLIT, drm_mach64_blit_t)
|
|
+#define DRM_IOCTL_MACH64_FLUSH DRM_IO( DRM_COMMAND_BASE + DRM_MACH64_FLUSH )
|
|
+#define DRM_IOCTL_MACH64_GETPARAM DRM_IOWR( DRM_COMMAND_BASE + DRM_MACH64_GETPARAM, drm_mach64_getparam_t)
|
|
+
|
|
+/* Buffer flags for clears
|
|
+ */
|
|
+#define MACH64_FRONT 0x1
|
|
+#define MACH64_BACK 0x2
|
|
+#define MACH64_DEPTH 0x4
|
|
+
|
|
+/* Primitive types for vertex buffers
|
|
+ */
|
|
+#define MACH64_PRIM_POINTS 0x00000000
|
|
+#define MACH64_PRIM_LINES 0x00000001
|
|
+#define MACH64_PRIM_LINE_LOOP 0x00000002
|
|
+#define MACH64_PRIM_LINE_STRIP 0x00000003
|
|
+#define MACH64_PRIM_TRIANGLES 0x00000004
|
|
+#define MACH64_PRIM_TRIANGLE_STRIP 0x00000005
|
|
+#define MACH64_PRIM_TRIANGLE_FAN 0x00000006
|
|
+#define MACH64_PRIM_QUADS 0x00000007
|
|
+#define MACH64_PRIM_QUAD_STRIP 0x00000008
|
|
+#define MACH64_PRIM_POLYGON 0x00000009
|
|
+
|
|
+typedef enum _drm_mach64_dma_mode_t {
|
|
+ MACH64_MODE_DMA_ASYNC,
|
|
+ MACH64_MODE_DMA_SYNC,
|
|
+ MACH64_MODE_MMIO
|
|
+} drm_mach64_dma_mode_t;
|
|
+
|
|
+typedef struct drm_mach64_init {
|
|
+ enum {
|
|
+ DRM_MACH64_INIT_DMA = 0x01,
|
|
+ DRM_MACH64_CLEANUP_DMA = 0x02
|
|
+ } func;
|
|
+
|
|
+ unsigned long sarea_priv_offset;
|
|
+ int is_pci;
|
|
+ drm_mach64_dma_mode_t dma_mode;
|
|
+
|
|
+ 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 long fb_offset;
|
|
+ unsigned long mmio_offset;
|
|
+ unsigned long ring_offset;
|
|
+ unsigned long buffers_offset;
|
|
+ unsigned long agp_textures_offset;
|
|
+} drm_mach64_init_t;
|
|
+
|
|
+typedef struct drm_mach64_clear {
|
|
+ unsigned int flags;
|
|
+ int x, y, w, h;
|
|
+ unsigned int clear_color;
|
|
+ unsigned int clear_depth;
|
|
+} drm_mach64_clear_t;
|
|
+
|
|
+typedef struct drm_mach64_vertex {
|
|
+ int prim;
|
|
+ void *buf; /* Address of vertex buffer */
|
|
+ unsigned long used; /* Number of bytes in buffer */
|
|
+ int discard; /* Client finished with buffer? */
|
|
+} drm_mach64_vertex_t;
|
|
+
|
|
+typedef struct drm_mach64_blit {
|
|
+ void *buf;
|
|
+ int pitch;
|
|
+ int offset;
|
|
+ int format;
|
|
+ unsigned short x, y;
|
|
+ unsigned short width, height;
|
|
+} drm_mach64_blit_t;
|
|
+
|
|
+typedef struct drm_mach64_getparam {
|
|
+ enum {
|
|
+ MACH64_PARAM_FRAMES_QUEUED = 0x01,
|
|
+ MACH64_PARAM_IRQ_NR = 0x02
|
|
+ } param;
|
|
+ void *value;
|
|
+} drm_mach64_getparam_t;
|
|
+
|
|
+#endif
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/mach64/mach64_drv.c
|
|
@@ -0,0 +1,105 @@
|
|
+/* mach64_drv.c -- mach64 (Rage Pro) driver -*- linux-c -*-
|
|
+ * Created: Fri Nov 24 18:34:32 2000 by gareth@valinux.com
|
|
+ *
|
|
+ * Copyright 2000 Gareth Hughes
|
|
+ * 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
|
|
+ * GARETH HUGHES 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>
|
|
+ * Leif Delgass <ldelgass@retinalburn.net>
|
|
+ */
|
|
+
|
|
+#include "drmP.h"
|
|
+#include "drm.h"
|
|
+#include "mach64_drm.h"
|
|
+#include "mach64_drv.h"
|
|
+
|
|
+#include "drm_pciids.h"
|
|
+
|
|
+static struct pci_device_id pciidlist[] = {
|
|
+ mach64_PCI_IDS
|
|
+};
|
|
+
|
|
+static int probe(struct pci_dev *pdev, const struct pci_device_id *ent);
|
|
+static struct drm_driver driver = {
|
|
+ .driver_features =
|
|
+ DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_HAVE_DMA
|
|
+ | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
|
|
+ .lastclose = mach64_driver_lastclose,
|
|
+ .get_vblank_counter = mach64_get_vblank_counter,
|
|
+ .enable_vblank = mach64_enable_vblank,
|
|
+ .disable_vblank = mach64_disable_vblank,
|
|
+ .irq_preinstall = mach64_driver_irq_preinstall,
|
|
+ .irq_postinstall = mach64_driver_irq_postinstall,
|
|
+ .irq_uninstall = mach64_driver_irq_uninstall,
|
|
+ .irq_handler = mach64_driver_irq_handler,
|
|
+ .reclaim_buffers = drm_core_reclaim_buffers,
|
|
+ .get_map_ofs = drm_core_get_map_ofs,
|
|
+ .get_reg_ofs = drm_core_get_reg_ofs,
|
|
+ .ioctls = mach64_ioctls,
|
|
+ .dma_ioctl = mach64_dma_buffers,
|
|
+ .fops = {
|
|
+ .owner = THIS_MODULE,
|
|
+ .open = drm_open,
|
|
+ .release = drm_release,
|
|
+ .ioctl = drm_ioctl,
|
|
+ .mmap = drm_mmap,
|
|
+ .poll = drm_poll,
|
|
+ .fasync = drm_fasync,
|
|
+ },
|
|
+ .pci_driver = {
|
|
+ .name = DRIVER_NAME,
|
|
+ .id_table = pciidlist,
|
|
+ .probe = probe,
|
|
+ .remove = __devexit_p(drm_cleanup_pci),
|
|
+ },
|
|
+
|
|
+ .name = DRIVER_NAME,
|
|
+ .desc = DRIVER_DESC,
|
|
+ .date = DRIVER_DATE,
|
|
+ .major = DRIVER_MAJOR,
|
|
+ .minor = DRIVER_MINOR,
|
|
+ .patchlevel = DRIVER_PATCHLEVEL,
|
|
+};
|
|
+
|
|
+static int probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
+{
|
|
+ return drm_get_dev(pdev, ent, &driver);
|
|
+}
|
|
+
|
|
+
|
|
+static int __init mach64_init(void)
|
|
+{
|
|
+ driver.num_ioctls = mach64_max_ioctl;
|
|
+ return drm_init(&driver, pciidlist);
|
|
+}
|
|
+
|
|
+static void __exit mach64_exit(void)
|
|
+{
|
|
+ drm_exit(&driver);
|
|
+}
|
|
+
|
|
+module_init(mach64_init);
|
|
+module_exit(mach64_exit);
|
|
+
|
|
+MODULE_AUTHOR(DRIVER_AUTHOR);
|
|
+MODULE_DESCRIPTION(DRIVER_DESC);
|
|
+MODULE_LICENSE("GPL and additional rights");
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/mach64/mach64_drv.h
|
|
@@ -0,0 +1,859 @@
|
|
+/* mach64_drv.h -- Private header for mach64 driver -*- linux-c -*-
|
|
+ * Created: Fri Nov 24 22:07:58 2000 by gareth@valinux.com
|
|
+ */
|
|
+/*
|
|
+ * Copyright 2000 Gareth Hughes
|
|
+ * Copyright 2002 Frank C. Earl
|
|
+ * Copyright 2002-2003 Leif Delgass
|
|
+ * 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 COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Gareth Hughes <gareth@valinux.com>
|
|
+ * Frank C. Earl <fearl@airmail.net>
|
|
+ * Leif Delgass <ldelgass@retinalburn.net>
|
|
+ * José Fonseca <j_r_fonseca@yahoo.co.uk>
|
|
+ */
|
|
+
|
|
+#ifndef __MACH64_DRV_H__
|
|
+#define __MACH64_DRV_H__
|
|
+
|
|
+/* General customization:
|
|
+ */
|
|
+
|
|
+#define DRIVER_AUTHOR "Gareth Hughes, Leif Delgass, José Fonseca"
|
|
+
|
|
+#define DRIVER_NAME "mach64"
|
|
+#define DRIVER_DESC "DRM module for the ATI Rage Pro"
|
|
+#define DRIVER_DATE "20060718"
|
|
+
|
|
+#define DRIVER_MAJOR 2
|
|
+#define DRIVER_MINOR 0
|
|
+#define DRIVER_PATCHLEVEL 0
|
|
+
|
|
+/* FIXME: remove these when not needed */
|
|
+/* Development driver options */
|
|
+#define MACH64_EXTRA_CHECKING 0 /* Extra sanity checks for DMA/freelist management */
|
|
+#define MACH64_VERBOSE 0 /* Verbose debugging output */
|
|
+
|
|
+typedef struct drm_mach64_freelist {
|
|
+ struct list_head list; /* List pointers for free_list, placeholders, or pending list */
|
|
+ struct drm_buf *buf; /* Pointer to the buffer */
|
|
+ int discard; /* This flag is set when we're done (re)using a buffer */
|
|
+ u32 ring_ofs; /* dword offset in ring of last descriptor for this buffer */
|
|
+} drm_mach64_freelist_t;
|
|
+
|
|
+typedef struct drm_mach64_descriptor_ring {
|
|
+ void *start; /* write pointer (cpu address) to start of descriptor ring */
|
|
+ u32 start_addr; /* bus address of beginning of descriptor ring */
|
|
+ int size; /* size of ring in bytes */
|
|
+
|
|
+ u32 head_addr; /* bus address of descriptor ring head */
|
|
+ u32 head; /* dword offset of descriptor ring head */
|
|
+ u32 tail; /* dword offset of descriptor ring tail */
|
|
+ u32 tail_mask; /* mask used to wrap ring */
|
|
+ int space; /* number of free bytes in ring */
|
|
+} drm_mach64_descriptor_ring_t;
|
|
+
|
|
+typedef struct drm_mach64_private {
|
|
+ drm_mach64_sarea_t *sarea_priv;
|
|
+
|
|
+ int is_pci;
|
|
+ drm_mach64_dma_mode_t driver_mode; /* Async DMA, sync DMA, or MMIO */
|
|
+
|
|
+ int usec_timeout; /* Timeout for the wait functions */
|
|
+
|
|
+ drm_mach64_descriptor_ring_t ring; /* DMA descriptor table (ring buffer) */
|
|
+ int ring_running; /* Is bus mastering is enabled */
|
|
+
|
|
+ struct list_head free_list; /* Free-list head */
|
|
+ struct list_head placeholders; /* Placeholder list for buffers held by clients */
|
|
+ struct list_head pending; /* Buffers pending completion */
|
|
+
|
|
+ u32 frame_ofs[MACH64_MAX_QUEUED_FRAMES]; /* dword ring offsets of most recent frame swaps */
|
|
+
|
|
+ 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;
|
|
+
|
|
+ atomic_t vbl_received; /**< Number of vblanks received. */
|
|
+
|
|
+ u32 front_offset_pitch;
|
|
+ u32 back_offset_pitch;
|
|
+ u32 depth_offset_pitch;
|
|
+
|
|
+ drm_local_map_t *sarea;
|
|
+ drm_local_map_t *fb;
|
|
+ drm_local_map_t *mmio;
|
|
+ drm_local_map_t *ring_map;
|
|
+ drm_local_map_t *dev_buffers; /* this is a pointer to a structure in dev */
|
|
+ drm_local_map_t *agp_textures;
|
|
+} drm_mach64_private_t;
|
|
+
|
|
+extern struct drm_ioctl_desc mach64_ioctls[];
|
|
+extern int mach64_max_ioctl;
|
|
+
|
|
+ /* mach64_dma.c */
|
|
+extern int mach64_dma_init(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv);
|
|
+extern int mach64_dma_idle(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv);
|
|
+extern int mach64_dma_flush(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv);
|
|
+extern int mach64_engine_reset(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv);
|
|
+extern int mach64_dma_buffers(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv);
|
|
+extern void mach64_driver_lastclose(struct drm_device * dev);
|
|
+
|
|
+extern int mach64_init_freelist(struct drm_device * dev);
|
|
+extern void mach64_destroy_freelist(struct drm_device * dev);
|
|
+extern struct drm_buf *mach64_freelist_get(drm_mach64_private_t * dev_priv);
|
|
+extern int mach64_freelist_put(drm_mach64_private_t * dev_priv,
|
|
+ struct drm_buf * copy_buf);
|
|
+
|
|
+extern int mach64_do_wait_for_fifo(drm_mach64_private_t * dev_priv,
|
|
+ int entries);
|
|
+extern int mach64_do_wait_for_idle(drm_mach64_private_t * dev_priv);
|
|
+extern int mach64_wait_ring(drm_mach64_private_t * dev_priv, int n);
|
|
+extern int mach64_do_dispatch_pseudo_dma(drm_mach64_private_t * dev_priv);
|
|
+extern int mach64_do_release_used_buffers(drm_mach64_private_t * dev_priv);
|
|
+extern void mach64_dump_engine_info(drm_mach64_private_t * dev_priv);
|
|
+extern void mach64_dump_ring_info(drm_mach64_private_t * dev_priv);
|
|
+extern int mach64_do_engine_reset(drm_mach64_private_t * dev_priv);
|
|
+
|
|
+extern int mach64_add_buf_to_ring(drm_mach64_private_t *dev_priv,
|
|
+ drm_mach64_freelist_t *_entry);
|
|
+extern int mach64_add_hostdata_buf_to_ring(drm_mach64_private_t *dev_priv,
|
|
+ drm_mach64_freelist_t *_entry);
|
|
+
|
|
+extern int mach64_do_dma_idle(drm_mach64_private_t * dev_priv);
|
|
+extern int mach64_do_dma_flush(drm_mach64_private_t * dev_priv);
|
|
+extern int mach64_do_cleanup_dma(struct drm_device * dev);
|
|
+
|
|
+ /* mach64_state.c */
|
|
+extern int mach64_dma_clear(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv);
|
|
+extern int mach64_dma_swap(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv);
|
|
+extern int mach64_dma_vertex(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv);
|
|
+extern int mach64_dma_blit(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv);
|
|
+extern int mach64_get_param(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv);
|
|
+
|
|
+extern u32 mach64_get_vblank_counter(struct drm_device *dev, int crtc);
|
|
+extern int mach64_enable_vblank(struct drm_device *dev, int crtc);
|
|
+extern void mach64_disable_vblank(struct drm_device *dev, int crtc);
|
|
+extern irqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS);
|
|
+extern void mach64_driver_irq_preinstall(struct drm_device *dev);
|
|
+extern int mach64_driver_irq_postinstall(struct drm_device *dev);
|
|
+extern void mach64_driver_irq_uninstall(struct drm_device *dev);
|
|
+
|
|
+/* ================================================================
|
|
+ * Registers
|
|
+ */
|
|
+
|
|
+#define MACH64_AGP_BASE 0x0148
|
|
+#define MACH64_AGP_CNTL 0x014c
|
|
+#define MACH64_ALPHA_TST_CNTL 0x0550
|
|
+
|
|
+#define MACH64_DSP_CONFIG 0x0420
|
|
+#define MACH64_DSP_ON_OFF 0x0424
|
|
+#define MACH64_EXT_MEM_CNTL 0x04ac
|
|
+#define MACH64_GEN_TEST_CNTL 0x04d0
|
|
+#define MACH64_HW_DEBUG 0x047c
|
|
+#define MACH64_MEM_ADDR_CONFIG 0x0434
|
|
+#define MACH64_MEM_BUF_CNTL 0x042c
|
|
+#define MACH64_MEM_CNTL 0x04b0
|
|
+
|
|
+#define MACH64_BM_ADDR 0x0648
|
|
+#define MACH64_BM_COMMAND 0x0188
|
|
+#define MACH64_BM_DATA 0x0648
|
|
+#define MACH64_BM_FRAME_BUF_OFFSET 0x0180
|
|
+#define MACH64_BM_GUI_TABLE 0x01b8
|
|
+#define MACH64_BM_GUI_TABLE_CMD 0x064c
|
|
+# define MACH64_CIRCULAR_BUF_SIZE_16KB (0 << 0)
|
|
+# define MACH64_CIRCULAR_BUF_SIZE_32KB (1 << 0)
|
|
+# define MACH64_CIRCULAR_BUF_SIZE_64KB (2 << 0)
|
|
+# define MACH64_CIRCULAR_BUF_SIZE_128KB (3 << 0)
|
|
+# define MACH64_LAST_DESCRIPTOR (1 << 31)
|
|
+#define MACH64_BM_HOSTDATA 0x0644
|
|
+#define MACH64_BM_STATUS 0x018c
|
|
+#define MACH64_BM_SYSTEM_MEM_ADDR 0x0184
|
|
+#define MACH64_BM_SYSTEM_TABLE 0x01bc
|
|
+#define MACH64_BUS_CNTL 0x04a0
|
|
+# define MACH64_BUS_MSTR_RESET (1 << 1)
|
|
+# define MACH64_BUS_APER_REG_DIS (1 << 4)
|
|
+# define MACH64_BUS_FLUSH_BUF (1 << 2)
|
|
+# define MACH64_BUS_MASTER_DIS (1 << 6)
|
|
+# define MACH64_BUS_EXT_REG_EN (1 << 27)
|
|
+
|
|
+#define MACH64_CLR_CMP_CLR 0x0700
|
|
+#define MACH64_CLR_CMP_CNTL 0x0708
|
|
+#define MACH64_CLR_CMP_MASK 0x0704
|
|
+#define MACH64_CONFIG_CHIP_ID 0x04e0
|
|
+#define MACH64_CONFIG_CNTL 0x04dc
|
|
+#define MACH64_CONFIG_STAT0 0x04e4
|
|
+#define MACH64_CONFIG_STAT1 0x0494
|
|
+#define MACH64_CONFIG_STAT2 0x0498
|
|
+#define MACH64_CONTEXT_LOAD_CNTL 0x072c
|
|
+#define MACH64_CONTEXT_MASK 0x0720
|
|
+#define MACH64_COMPOSITE_SHADOW_ID 0x0798
|
|
+#define MACH64_CRC_SIG 0x04e8
|
|
+#define MACH64_CUSTOM_MACRO_CNTL 0x04d4
|
|
+
|
|
+#define MACH64_DP_BKGD_CLR 0x06c0
|
|
+#define MACH64_DP_FOG_CLR 0x06c4
|
|
+#define MACH64_DP_FGRD_BKGD_CLR 0x06e0
|
|
+#define MACH64_DP_FRGD_CLR 0x06c4
|
|
+#define MACH64_DP_FGRD_CLR_MIX 0x06dc
|
|
+
|
|
+#define MACH64_DP_MIX 0x06d4
|
|
+# define BKGD_MIX_NOT_D (0 << 0)
|
|
+# define BKGD_MIX_ZERO (1 << 0)
|
|
+# define BKGD_MIX_ONE (2 << 0)
|
|
+# define MACH64_BKGD_MIX_D (3 << 0)
|
|
+# define BKGD_MIX_NOT_S (4 << 0)
|
|
+# define BKGD_MIX_D_XOR_S (5 << 0)
|
|
+# define BKGD_MIX_NOT_D_XOR_S (6 << 0)
|
|
+# define MACH64_BKGD_MIX_S (7 << 0)
|
|
+# define BKGD_MIX_NOT_D_OR_NOT_S (8 << 0)
|
|
+# define BKGD_MIX_D_OR_NOT_S (9 << 0)
|
|
+# define BKGD_MIX_NOT_D_OR_S (10 << 0)
|
|
+# define BKGD_MIX_D_OR_S (11 << 0)
|
|
+# define BKGD_MIX_D_AND_S (12 << 0)
|
|
+# define BKGD_MIX_NOT_D_AND_S (13 << 0)
|
|
+# define BKGD_MIX_D_AND_NOT_S (14 << 0)
|
|
+# define BKGD_MIX_NOT_D_AND_NOT_S (15 << 0)
|
|
+# define BKGD_MIX_D_PLUS_S_DIV2 (23 << 0)
|
|
+# define FRGD_MIX_NOT_D (0 << 16)
|
|
+# define FRGD_MIX_ZERO (1 << 16)
|
|
+# define FRGD_MIX_ONE (2 << 16)
|
|
+# define FRGD_MIX_D (3 << 16)
|
|
+# define FRGD_MIX_NOT_S (4 << 16)
|
|
+# define FRGD_MIX_D_XOR_S (5 << 16)
|
|
+# define FRGD_MIX_NOT_D_XOR_S (6 << 16)
|
|
+# define MACH64_FRGD_MIX_S (7 << 16)
|
|
+# define FRGD_MIX_NOT_D_OR_NOT_S (8 << 16)
|
|
+# define FRGD_MIX_D_OR_NOT_S (9 << 16)
|
|
+# define FRGD_MIX_NOT_D_OR_S (10 << 16)
|
|
+# define FRGD_MIX_D_OR_S (11 << 16)
|
|
+# define FRGD_MIX_D_AND_S (12 << 16)
|
|
+# define FRGD_MIX_NOT_D_AND_S (13 << 16)
|
|
+# define FRGD_MIX_D_AND_NOT_S (14 << 16)
|
|
+# define FRGD_MIX_NOT_D_AND_NOT_S (15 << 16)
|
|
+# define FRGD_MIX_D_PLUS_S_DIV2 (23 << 16)
|
|
+
|
|
+#define MACH64_DP_PIX_WIDTH 0x06d0
|
|
+# define MACH64_HOST_TRIPLE_ENABLE (1 << 13)
|
|
+# define MACH64_BYTE_ORDER_MSB_TO_LSB (0 << 24)
|
|
+# define MACH64_BYTE_ORDER_LSB_TO_MSB (1 << 24)
|
|
+
|
|
+#define MACH64_DP_SRC 0x06d8
|
|
+# define MACH64_BKGD_SRC_BKGD_CLR (0 << 0)
|
|
+# define MACH64_BKGD_SRC_FRGD_CLR (1 << 0)
|
|
+# define MACH64_BKGD_SRC_HOST (2 << 0)
|
|
+# define MACH64_BKGD_SRC_BLIT (3 << 0)
|
|
+# define MACH64_BKGD_SRC_PATTERN (4 << 0)
|
|
+# define MACH64_BKGD_SRC_3D (5 << 0)
|
|
+# define MACH64_FRGD_SRC_BKGD_CLR (0 << 8)
|
|
+# define MACH64_FRGD_SRC_FRGD_CLR (1 << 8)
|
|
+# define MACH64_FRGD_SRC_HOST (2 << 8)
|
|
+# define MACH64_FRGD_SRC_BLIT (3 << 8)
|
|
+# define MACH64_FRGD_SRC_PATTERN (4 << 8)
|
|
+# define MACH64_FRGD_SRC_3D (5 << 8)
|
|
+# define MACH64_MONO_SRC_ONE (0 << 16)
|
|
+# define MACH64_MONO_SRC_PATTERN (1 << 16)
|
|
+# define MACH64_MONO_SRC_HOST (2 << 16)
|
|
+# define MACH64_MONO_SRC_BLIT (3 << 16)
|
|
+
|
|
+#define MACH64_DP_WRITE_MASK 0x06c8
|
|
+
|
|
+#define MACH64_DST_CNTL 0x0530
|
|
+# define MACH64_DST_X_RIGHT_TO_LEFT (0 << 0)
|
|
+# define MACH64_DST_X_LEFT_TO_RIGHT (1 << 0)
|
|
+# define MACH64_DST_Y_BOTTOM_TO_TOP (0 << 1)
|
|
+# define MACH64_DST_Y_TOP_TO_BOTTOM (1 << 1)
|
|
+# define MACH64_DST_X_MAJOR (0 << 2)
|
|
+# define MACH64_DST_Y_MAJOR (1 << 2)
|
|
+# define MACH64_DST_X_TILE (1 << 3)
|
|
+# define MACH64_DST_Y_TILE (1 << 4)
|
|
+# define MACH64_DST_LAST_PEL (1 << 5)
|
|
+# define MACH64_DST_POLYGON_ENABLE (1 << 6)
|
|
+# define MACH64_DST_24_ROTATION_ENABLE (1 << 7)
|
|
+
|
|
+#define MACH64_DST_HEIGHT_WIDTH 0x0518
|
|
+#define MACH64_DST_OFF_PITCH 0x0500
|
|
+#define MACH64_DST_WIDTH_HEIGHT 0x06ec
|
|
+#define MACH64_DST_X_Y 0x06e8
|
|
+#define MACH64_DST_Y_X 0x050c
|
|
+
|
|
+#define MACH64_FIFO_STAT 0x0710
|
|
+# define MACH64_FIFO_SLOT_MASK 0x0000ffff
|
|
+# define MACH64_FIFO_ERR (1 << 31)
|
|
+
|
|
+#define MACH64_GEN_TEST_CNTL 0x04d0
|
|
+# define MACH64_GUI_ENGINE_ENABLE (1 << 8)
|
|
+#define MACH64_GUI_CMDFIFO_DEBUG 0x0170
|
|
+#define MACH64_GUI_CMDFIFO_DATA 0x0174
|
|
+#define MACH64_GUI_CNTL 0x0178
|
|
+# define MACH64_CMDFIFO_SIZE_MASK 0x00000003ul
|
|
+# define MACH64_CMDFIFO_SIZE_192 0x00000000ul
|
|
+# define MACH64_CMDFIFO_SIZE_128 0x00000001ul
|
|
+# define MACH64_CMDFIFO_SIZE_64 0x00000002ul
|
|
+#define MACH64_GUI_STAT 0x0738
|
|
+# define MACH64_GUI_ACTIVE (1 << 0)
|
|
+#define MACH64_GUI_TRAJ_CNTL 0x0730
|
|
+
|
|
+#define MACH64_HOST_CNTL 0x0640
|
|
+#define MACH64_HOST_DATA0 0x0600
|
|
+
|
|
+#define MACH64_ONE_OVER_AREA 0x029c
|
|
+#define MACH64_ONE_OVER_AREA_UC 0x0300
|
|
+
|
|
+#define MACH64_PAT_REG0 0x0680
|
|
+#define MACH64_PAT_REG1 0x0684
|
|
+
|
|
+#define MACH64_SC_LEFT 0x06a0
|
|
+#define MACH64_SC_RIGHT 0x06a4
|
|
+#define MACH64_SC_LEFT_RIGHT 0x06a8
|
|
+#define MACH64_SC_TOP 0x06ac
|
|
+#define MACH64_SC_BOTTOM 0x06b0
|
|
+#define MACH64_SC_TOP_BOTTOM 0x06b4
|
|
+
|
|
+#define MACH64_SCALE_3D_CNTL 0x05fc
|
|
+#define MACH64_SCRATCH_REG0 0x0480
|
|
+#define MACH64_SCRATCH_REG1 0x0484
|
|
+#define MACH64_SECONDARY_TEX_OFF 0x0778
|
|
+#define MACH64_SETUP_CNTL 0x0304
|
|
+#define MACH64_SRC_CNTL 0x05b4
|
|
+# define MACH64_SRC_BM_ENABLE (1 << 8)
|
|
+# define MACH64_SRC_BM_SYNC (1 << 9)
|
|
+# define MACH64_SRC_BM_OP_FRAME_TO_SYSTEM (0 << 10)
|
|
+# define MACH64_SRC_BM_OP_SYSTEM_TO_FRAME (1 << 10)
|
|
+# define MACH64_SRC_BM_OP_REG_TO_SYSTEM (2 << 10)
|
|
+# define MACH64_SRC_BM_OP_SYSTEM_TO_REG (3 << 10)
|
|
+#define MACH64_SRC_HEIGHT1 0x0594
|
|
+#define MACH64_SRC_HEIGHT2 0x05ac
|
|
+#define MACH64_SRC_HEIGHT1_WIDTH1 0x0598
|
|
+#define MACH64_SRC_HEIGHT2_WIDTH2 0x05b0
|
|
+#define MACH64_SRC_OFF_PITCH 0x0580
|
|
+#define MACH64_SRC_WIDTH1 0x0590
|
|
+#define MACH64_SRC_Y_X 0x058c
|
|
+
|
|
+#define MACH64_TEX_0_OFF 0x05c0
|
|
+#define MACH64_TEX_CNTL 0x0774
|
|
+#define MACH64_TEX_SIZE_PITCH 0x0770
|
|
+#define MACH64_TIMER_CONFIG 0x0428
|
|
+
|
|
+#define MACH64_VERTEX_1_ARGB 0x0254
|
|
+#define MACH64_VERTEX_1_S 0x0240
|
|
+#define MACH64_VERTEX_1_SECONDARY_S 0x0328
|
|
+#define MACH64_VERTEX_1_SECONDARY_T 0x032c
|
|
+#define MACH64_VERTEX_1_SECONDARY_W 0x0330
|
|
+#define MACH64_VERTEX_1_SPEC_ARGB 0x024c
|
|
+#define MACH64_VERTEX_1_T 0x0244
|
|
+#define MACH64_VERTEX_1_W 0x0248
|
|
+#define MACH64_VERTEX_1_X_Y 0x0258
|
|
+#define MACH64_VERTEX_1_Z 0x0250
|
|
+#define MACH64_VERTEX_2_ARGB 0x0274
|
|
+#define MACH64_VERTEX_2_S 0x0260
|
|
+#define MACH64_VERTEX_2_SECONDARY_S 0x0334
|
|
+#define MACH64_VERTEX_2_SECONDARY_T 0x0338
|
|
+#define MACH64_VERTEX_2_SECONDARY_W 0x033c
|
|
+#define MACH64_VERTEX_2_SPEC_ARGB 0x026c
|
|
+#define MACH64_VERTEX_2_T 0x0264
|
|
+#define MACH64_VERTEX_2_W 0x0268
|
|
+#define MACH64_VERTEX_2_X_Y 0x0278
|
|
+#define MACH64_VERTEX_2_Z 0x0270
|
|
+#define MACH64_VERTEX_3_ARGB 0x0294
|
|
+#define MACH64_VERTEX_3_S 0x0280
|
|
+#define MACH64_VERTEX_3_SECONDARY_S 0x02a0
|
|
+#define MACH64_VERTEX_3_SECONDARY_T 0x02a4
|
|
+#define MACH64_VERTEX_3_SECONDARY_W 0x02a8
|
|
+#define MACH64_VERTEX_3_SPEC_ARGB 0x028c
|
|
+#define MACH64_VERTEX_3_T 0x0284
|
|
+#define MACH64_VERTEX_3_W 0x0288
|
|
+#define MACH64_VERTEX_3_X_Y 0x0298
|
|
+#define MACH64_VERTEX_3_Z 0x0290
|
|
+
|
|
+#define MACH64_Z_CNTL 0x054c
|
|
+#define MACH64_Z_OFF_PITCH 0x0548
|
|
+
|
|
+#define MACH64_CRTC_VLINE_CRNT_VLINE 0x0410
|
|
+# define MACH64_CRTC_VLINE_MASK 0x000007ff
|
|
+# define MACH64_CRTC_CRNT_VLINE_MASK 0x07ff0000
|
|
+#define MACH64_CRTC_OFF_PITCH 0x0414
|
|
+#define MACH64_CRTC_INT_CNTL 0x0418
|
|
+# define MACH64_CRTC_VBLANK (1 << 0)
|
|
+# define MACH64_CRTC_VBLANK_INT_EN (1 << 1)
|
|
+# define MACH64_CRTC_VBLANK_INT (1 << 2)
|
|
+# define MACH64_CRTC_VLINE_INT_EN (1 << 3)
|
|
+# define MACH64_CRTC_VLINE_INT (1 << 4)
|
|
+# define MACH64_CRTC_VLINE_SYNC (1 << 5) /* 0=even, 1=odd */
|
|
+# define MACH64_CRTC_FRAME (1 << 6) /* 0=even, 1=odd */
|
|
+# define MACH64_CRTC_SNAPSHOT_INT_EN (1 << 7)
|
|
+# define MACH64_CRTC_SNAPSHOT_INT (1 << 8)
|
|
+# define MACH64_CRTC_I2C_INT_EN (1 << 9)
|
|
+# define MACH64_CRTC_I2C_INT (1 << 10)
|
|
+# define MACH64_CRTC2_VBLANK (1 << 11) /* LT Pro */
|
|
+# define MACH64_CRTC2_VBLANK_INT_EN (1 << 12) /* LT Pro */
|
|
+# define MACH64_CRTC2_VBLANK_INT (1 << 13) /* LT Pro */
|
|
+# define MACH64_CRTC2_VLINE_INT_EN (1 << 14) /* LT Pro */
|
|
+# define MACH64_CRTC2_VLINE_INT (1 << 15) /* LT Pro */
|
|
+# define MACH64_CRTC_CAPBUF0_INT_EN (1 << 16)
|
|
+# define MACH64_CRTC_CAPBUF0_INT (1 << 17)
|
|
+# define MACH64_CRTC_CAPBUF1_INT_EN (1 << 18)
|
|
+# define MACH64_CRTC_CAPBUF1_INT (1 << 19)
|
|
+# define MACH64_CRTC_OVERLAY_EOF_INT_EN (1 << 20)
|
|
+# define MACH64_CRTC_OVERLAY_EOF_INT (1 << 21)
|
|
+# define MACH64_CRTC_ONESHOT_CAP_INT_EN (1 << 22)
|
|
+# define MACH64_CRTC_ONESHOT_CAP_INT (1 << 23)
|
|
+# define MACH64_CRTC_BUSMASTER_EOL_INT_EN (1 << 24)
|
|
+# define MACH64_CRTC_BUSMASTER_EOL_INT (1 << 25)
|
|
+# define MACH64_CRTC_GP_INT_EN (1 << 26)
|
|
+# define MACH64_CRTC_GP_INT (1 << 27)
|
|
+# define MACH64_CRTC2_VLINE_SYNC (1 << 28) /* LT Pro */ /* 0=even, 1=odd */
|
|
+# define MACH64_CRTC_SNAPSHOT2_INT_EN (1 << 29) /* LT Pro */
|
|
+# define MACH64_CRTC_SNAPSHOT2_INT (1 << 30) /* LT Pro */
|
|
+# define MACH64_CRTC_VBLANK2_INT (1 << 31)
|
|
+# define MACH64_CRTC_INT_ENS \
|
|
+ ( \
|
|
+ MACH64_CRTC_VBLANK_INT_EN | \
|
|
+ MACH64_CRTC_VLINE_INT_EN | \
|
|
+ MACH64_CRTC_SNAPSHOT_INT_EN | \
|
|
+ MACH64_CRTC_I2C_INT_EN | \
|
|
+ MACH64_CRTC2_VBLANK_INT_EN | \
|
|
+ MACH64_CRTC2_VLINE_INT_EN | \
|
|
+ MACH64_CRTC_CAPBUF0_INT_EN | \
|
|
+ MACH64_CRTC_CAPBUF1_INT_EN | \
|
|
+ MACH64_CRTC_OVERLAY_EOF_INT_EN | \
|
|
+ MACH64_CRTC_ONESHOT_CAP_INT_EN | \
|
|
+ MACH64_CRTC_BUSMASTER_EOL_INT_EN | \
|
|
+ MACH64_CRTC_GP_INT_EN | \
|
|
+ MACH64_CRTC_SNAPSHOT2_INT_EN | \
|
|
+ 0 \
|
|
+ )
|
|
+# define MACH64_CRTC_INT_ACKS \
|
|
+ ( \
|
|
+ MACH64_CRTC_VBLANK_INT | \
|
|
+ MACH64_CRTC_VLINE_INT | \
|
|
+ MACH64_CRTC_SNAPSHOT_INT | \
|
|
+ MACH64_CRTC_I2C_INT | \
|
|
+ MACH64_CRTC2_VBLANK_INT | \
|
|
+ MACH64_CRTC2_VLINE_INT | \
|
|
+ MACH64_CRTC_CAPBUF0_INT | \
|
|
+ MACH64_CRTC_CAPBUF1_INT | \
|
|
+ MACH64_CRTC_OVERLAY_EOF_INT | \
|
|
+ MACH64_CRTC_ONESHOT_CAP_INT | \
|
|
+ MACH64_CRTC_BUSMASTER_EOL_INT | \
|
|
+ MACH64_CRTC_GP_INT | \
|
|
+ MACH64_CRTC_SNAPSHOT2_INT | \
|
|
+ MACH64_CRTC_VBLANK2_INT | \
|
|
+ 0 \
|
|
+ )
|
|
+
|
|
+#define MACH64_DATATYPE_CI8 2
|
|
+#define MACH64_DATATYPE_ARGB1555 3
|
|
+#define MACH64_DATATYPE_RGB565 4
|
|
+#define MACH64_DATATYPE_ARGB8888 6
|
|
+#define MACH64_DATATYPE_RGB332 7
|
|
+#define MACH64_DATATYPE_Y8 8
|
|
+#define MACH64_DATATYPE_RGB8 9
|
|
+#define MACH64_DATATYPE_VYUY422 11
|
|
+#define MACH64_DATATYPE_YVYU422 12
|
|
+#define MACH64_DATATYPE_AYUV444 14
|
|
+#define MACH64_DATATYPE_ARGB4444 15
|
|
+
|
|
+#define MACH64_READ(reg) DRM_READ32(dev_priv->mmio, (reg) )
|
|
+#define MACH64_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio, (reg), (val) )
|
|
+
|
|
+#define DWMREG0 0x0400
|
|
+#define DWMREG0_END 0x07ff
|
|
+#define DWMREG1 0x0000
|
|
+#define DWMREG1_END 0x03ff
|
|
+
|
|
+#define ISREG0(r) (((r) >= DWMREG0) && ((r) <= DWMREG0_END))
|
|
+#define DMAREG0(r) (((r) - DWMREG0) >> 2)
|
|
+#define DMAREG1(r) ((((r) - DWMREG1) >> 2 ) | 0x0100)
|
|
+#define DMAREG(r) (ISREG0(r) ? DMAREG0(r) : DMAREG1(r))
|
|
+
|
|
+#define MMREG0 0x0000
|
|
+#define MMREG0_END 0x00ff
|
|
+
|
|
+#define ISMMREG0(r) (((r) >= MMREG0) && ((r) <= MMREG0_END))
|
|
+#define MMSELECT0(r) (((r) << 2) + DWMREG0)
|
|
+#define MMSELECT1(r) (((((r) & 0xff) << 2) + DWMREG1))
|
|
+#define MMSELECT(r) (ISMMREG0(r) ? MMSELECT0(r) : MMSELECT1(r))
|
|
+
|
|
+/* ================================================================
|
|
+ * DMA constants
|
|
+ */
|
|
+
|
|
+/* DMA descriptor field indices:
|
|
+ * The descriptor fields are loaded into the read-only
|
|
+ * BM_* system bus master registers during a bus-master operation
|
|
+ */
|
|
+#define MACH64_DMA_FRAME_BUF_OFFSET 0 /* BM_FRAME_BUF_OFFSET */
|
|
+#define MACH64_DMA_SYS_MEM_ADDR 1 /* BM_SYSTEM_MEM_ADDR */
|
|
+#define MACH64_DMA_COMMAND 2 /* BM_COMMAND */
|
|
+#define MACH64_DMA_RESERVED 3 /* BM_STATUS */
|
|
+
|
|
+/* BM_COMMAND descriptor field flags */
|
|
+#define MACH64_DMA_HOLD_OFFSET (1<<30) /* Don't increment DMA_FRAME_BUF_OFFSET */
|
|
+#define MACH64_DMA_EOL (1<<31) /* End of descriptor list flag */
|
|
+
|
|
+#define MACH64_DMA_CHUNKSIZE 0x1000 /* 4kB per DMA descriptor */
|
|
+#define MACH64_APERTURE_OFFSET 0x7ff800 /* frame-buffer offset for gui-masters */
|
|
+
|
|
+/* ================================================================
|
|
+ * Ring operations
|
|
+ *
|
|
+ * Since the Mach64 bus master engine requires polling, these functions end
|
|
+ * up being called frequently, hence being inline.
|
|
+ */
|
|
+
|
|
+static __inline__ void mach64_ring_start(drm_mach64_private_t * dev_priv)
|
|
+{
|
|
+ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
|
|
+
|
|
+ DRM_DEBUG("head_addr: 0x%08x head: %d tail: %d space: %d\n",
|
|
+ ring->head_addr, ring->head, ring->tail, ring->space);
|
|
+
|
|
+ if (mach64_do_wait_for_idle(dev_priv) < 0) {
|
|
+ mach64_do_engine_reset(dev_priv);
|
|
+ }
|
|
+
|
|
+ if (dev_priv->driver_mode != MACH64_MODE_MMIO) {
|
|
+ /* enable bus mastering and block 1 registers */
|
|
+ MACH64_WRITE(MACH64_BUS_CNTL,
|
|
+ (MACH64_READ(MACH64_BUS_CNTL) &
|
|
+ ~MACH64_BUS_MASTER_DIS)
|
|
+ | MACH64_BUS_EXT_REG_EN);
|
|
+ mach64_do_wait_for_idle(dev_priv);
|
|
+ }
|
|
+
|
|
+ /* reset descriptor table ring head */
|
|
+ MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD,
|
|
+ ring->head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB);
|
|
+
|
|
+ dev_priv->ring_running = 1;
|
|
+}
|
|
+
|
|
+static __inline__ void mach64_ring_resume(drm_mach64_private_t * dev_priv,
|
|
+ drm_mach64_descriptor_ring_t * ring)
|
|
+{
|
|
+ DRM_DEBUG("head_addr: 0x%08x head: %d tail: %d space: %d\n",
|
|
+ ring->head_addr, ring->head, ring->tail, ring->space);
|
|
+
|
|
+ /* reset descriptor table ring head */
|
|
+ MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD,
|
|
+ ring->head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB);
|
|
+
|
|
+ if (dev_priv->driver_mode == MACH64_MODE_MMIO) {
|
|
+ mach64_do_dispatch_pseudo_dma(dev_priv);
|
|
+ } else {
|
|
+ /* enable GUI bus mastering, and sync the bus master to the GUI */
|
|
+ MACH64_WRITE(MACH64_SRC_CNTL,
|
|
+ MACH64_SRC_BM_ENABLE | MACH64_SRC_BM_SYNC |
|
|
+ MACH64_SRC_BM_OP_SYSTEM_TO_REG);
|
|
+
|
|
+ /* kick off the transfer */
|
|
+ MACH64_WRITE(MACH64_DST_HEIGHT_WIDTH, 0);
|
|
+ if (dev_priv->driver_mode == MACH64_MODE_DMA_SYNC) {
|
|
+ if ((mach64_do_wait_for_idle(dev_priv)) < 0) {
|
|
+ DRM_ERROR("idle failed, resetting engine\n");
|
|
+ mach64_dump_engine_info(dev_priv);
|
|
+ mach64_do_engine_reset(dev_priv);
|
|
+ return;
|
|
+ }
|
|
+ mach64_do_release_used_buffers(dev_priv);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Poll the ring head and make sure the bus master is alive.
|
|
+ *
|
|
+ * Mach64's bus master engine will stop if there are no more entries to process.
|
|
+ * This function polls the engine for the last processed entry and calls
|
|
+ * mach64_ring_resume if there is an unprocessed entry.
|
|
+ *
|
|
+ * Note also that, since we update the ring tail while the bus master engine is
|
|
+ * in operation, it is possible that the last tail update was too late to be
|
|
+ * processed, and the bus master engine stops at the previous tail position.
|
|
+ * Therefore it is important to call this function frequently.
|
|
+ */
|
|
+static __inline__ void mach64_ring_tick(drm_mach64_private_t * dev_priv,
|
|
+ drm_mach64_descriptor_ring_t * ring)
|
|
+{
|
|
+ DRM_DEBUG("head_addr: 0x%08x head: %d tail: %d space: %d\n",
|
|
+ ring->head_addr, ring->head, ring->tail, ring->space);
|
|
+
|
|
+ if (!dev_priv->ring_running) {
|
|
+ mach64_ring_start(dev_priv);
|
|
+
|
|
+ if (ring->head != ring->tail) {
|
|
+ mach64_ring_resume(dev_priv, ring);
|
|
+ }
|
|
+ } else {
|
|
+ /* GUI_ACTIVE must be read before BM_GUI_TABLE to
|
|
+ * correctly determine the ring head
|
|
+ */
|
|
+ int gui_active =
|
|
+ MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE;
|
|
+
|
|
+ ring->head_addr = MACH64_READ(MACH64_BM_GUI_TABLE) & 0xfffffff0;
|
|
+
|
|
+ if (gui_active) {
|
|
+ /* If not idle, BM_GUI_TABLE points one descriptor
|
|
+ * past the current head
|
|
+ */
|
|
+ if (ring->head_addr == ring->start_addr) {
|
|
+ ring->head_addr += ring->size;
|
|
+ }
|
|
+ ring->head_addr -= 4 * sizeof(u32);
|
|
+ }
|
|
+
|
|
+ if (ring->head_addr < ring->start_addr ||
|
|
+ ring->head_addr >= ring->start_addr + ring->size) {
|
|
+ DRM_ERROR("bad ring head address: 0x%08x\n",
|
|
+ ring->head_addr);
|
|
+ mach64_dump_ring_info(dev_priv);
|
|
+ mach64_do_engine_reset(dev_priv);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ring->head = (ring->head_addr - ring->start_addr) / sizeof(u32);
|
|
+
|
|
+ if (!gui_active && ring->head != ring->tail) {
|
|
+ mach64_ring_resume(dev_priv, ring);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static __inline__ void mach64_ring_stop(drm_mach64_private_t * dev_priv)
|
|
+{
|
|
+ DRM_DEBUG("head_addr: 0x%08x head: %d tail: %d space: %d\n",
|
|
+ dev_priv->ring.head_addr, dev_priv->ring.head,
|
|
+ dev_priv->ring.tail, dev_priv->ring.space);
|
|
+
|
|
+ /* restore previous SRC_CNTL to disable busmastering */
|
|
+ mach64_do_wait_for_fifo(dev_priv, 1);
|
|
+ MACH64_WRITE(MACH64_SRC_CNTL, 0);
|
|
+
|
|
+ /* disable busmastering but keep the block 1 registers enabled */
|
|
+ mach64_do_wait_for_idle(dev_priv);
|
|
+ MACH64_WRITE(MACH64_BUS_CNTL, MACH64_READ(MACH64_BUS_CNTL)
|
|
+ | MACH64_BUS_MASTER_DIS | MACH64_BUS_EXT_REG_EN);
|
|
+
|
|
+ dev_priv->ring_running = 0;
|
|
+}
|
|
+
|
|
+static __inline__ void
|
|
+mach64_update_ring_snapshot(drm_mach64_private_t * dev_priv)
|
|
+{
|
|
+ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
|
|
+
|
|
+ DRM_DEBUG("\n");
|
|
+
|
|
+ mach64_ring_tick(dev_priv, ring);
|
|
+
|
|
+ ring->space = (ring->head - ring->tail) * sizeof(u32);
|
|
+ if (ring->space <= 0) {
|
|
+ ring->space += ring->size;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* ================================================================
|
|
+ * DMA macros
|
|
+ *
|
|
+ * Mach64's ring buffer doesn't take register writes directly. These
|
|
+ * have to be written indirectly in DMA buffers. These macros simplify
|
|
+ * the task of setting up a buffer, writing commands to it, and
|
|
+ * queuing the buffer in the ring.
|
|
+ */
|
|
+
|
|
+#define DMALOCALS \
|
|
+ drm_mach64_freelist_t *_entry = NULL; \
|
|
+ struct drm_buf *_buf = NULL; \
|
|
+ u32 *_buf_wptr; int _outcount
|
|
+
|
|
+#define GETBUFPTR( __buf ) \
|
|
+((dev_priv->is_pci) ? \
|
|
+ ((u32 *)(__buf)->address) : \
|
|
+ ((u32 *)((char *)dev_priv->dev_buffers->handle + (__buf)->offset)))
|
|
+
|
|
+#define GETBUFADDR( __buf ) ((u32)(__buf)->bus_address)
|
|
+
|
|
+#define GETRINGOFFSET() (_entry->ring_ofs)
|
|
+
|
|
+static __inline__ int mach64_find_pending_buf_entry(drm_mach64_private_t *
|
|
+ dev_priv,
|
|
+ drm_mach64_freelist_t **
|
|
+ entry, struct drm_buf * buf)
|
|
+{
|
|
+ struct list_head *ptr;
|
|
+#if MACH64_EXTRA_CHECKING
|
|
+ if (list_empty(&dev_priv->pending)) {
|
|
+ DRM_ERROR("Empty pending list in \n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+#endif
|
|
+ ptr = dev_priv->pending.prev;
|
|
+ *entry = list_entry(ptr, drm_mach64_freelist_t, list);
|
|
+ while ((*entry)->buf != buf) {
|
|
+ if (ptr == &dev_priv->pending) {
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ ptr = ptr->prev;
|
|
+ *entry = list_entry(ptr, drm_mach64_freelist_t, list);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#define DMASETPTR( _p ) \
|
|
+do { \
|
|
+ _buf = (_p); \
|
|
+ _outcount = 0; \
|
|
+ _buf_wptr = GETBUFPTR( _buf ); \
|
|
+} while(0)
|
|
+
|
|
+/* FIXME: use a private set of smaller buffers for state emits, clears, and swaps? */
|
|
+#define DMAGETPTR( file_priv, dev_priv, n ) \
|
|
+do { \
|
|
+ if ( MACH64_VERBOSE ) { \
|
|
+ DRM_INFO( "DMAGETPTR( %d )\n", (n) ); \
|
|
+ } \
|
|
+ _buf = mach64_freelist_get( dev_priv ); \
|
|
+ if (_buf == NULL) { \
|
|
+ DRM_ERROR("couldn't get buffer in DMAGETPTR\n"); \
|
|
+ return -EAGAIN; \
|
|
+ } \
|
|
+ if (_buf->pending) { \
|
|
+ DRM_ERROR("pending buf in DMAGETPTR\n"); \
|
|
+ return -EFAULT; \
|
|
+ } \
|
|
+ _buf->file_priv = file_priv; \
|
|
+ _outcount = 0; \
|
|
+ \
|
|
+ _buf_wptr = GETBUFPTR( _buf ); \
|
|
+} while (0)
|
|
+
|
|
+#define DMAOUTREG( reg, val ) \
|
|
+do { \
|
|
+ if ( MACH64_VERBOSE ) { \
|
|
+ DRM_INFO( " DMAOUTREG( 0x%x = 0x%08x )\n", \
|
|
+ reg, val ); \
|
|
+ } \
|
|
+ _buf_wptr[_outcount++] = cpu_to_le32(DMAREG(reg)); \
|
|
+ _buf_wptr[_outcount++] = cpu_to_le32((val)); \
|
|
+ _buf->used += 8; \
|
|
+} while (0)
|
|
+
|
|
+#define DMAADVANCE( dev_priv, _discard ) \
|
|
+ do { \
|
|
+ struct list_head *ptr; \
|
|
+ int ret; \
|
|
+ \
|
|
+ if ( MACH64_VERBOSE ) { \
|
|
+ DRM_INFO( "DMAADVANCE() in \n" ); \
|
|
+ } \
|
|
+ \
|
|
+ if (_buf->used <= 0) { \
|
|
+ DRM_ERROR( "DMAADVANCE(): sending empty buf %d\n", \
|
|
+ _buf->idx ); \
|
|
+ return -EFAULT; \
|
|
+ } \
|
|
+ if (_buf->pending) { \
|
|
+ /* This is a resued buffer, so we need to find it in the pending list */ \
|
|
+ if ((ret = mach64_find_pending_buf_entry(dev_priv, &_entry, _buf))) { \
|
|
+ DRM_ERROR( "DMAADVANCE(): couldn't find pending buf %d\n", _buf->idx ); \
|
|
+ return ret; \
|
|
+ } \
|
|
+ if (_entry->discard) { \
|
|
+ DRM_ERROR( "DMAADVANCE(): sending discarded pending buf %d\n", _buf->idx ); \
|
|
+ return -EFAULT; \
|
|
+ } \
|
|
+ } else { \
|
|
+ if (list_empty(&dev_priv->placeholders)) { \
|
|
+ DRM_ERROR( "DMAADVANCE(): empty placeholder list\n"); \
|
|
+ return -EFAULT; \
|
|
+ } \
|
|
+ ptr = dev_priv->placeholders.next; \
|
|
+ list_del(ptr); \
|
|
+ _entry = list_entry(ptr, drm_mach64_freelist_t, list); \
|
|
+ _buf->pending = 1; \
|
|
+ _entry->buf = _buf; \
|
|
+ list_add_tail(ptr, &dev_priv->pending); \
|
|
+ } \
|
|
+ _entry->discard = (_discard); \
|
|
+ if ((ret = mach64_add_buf_to_ring( dev_priv, _entry ))) \
|
|
+ return ret; \
|
|
+ } while (0)
|
|
+
|
|
+#define DMADISCARDBUF() \
|
|
+ do { \
|
|
+ if (_entry == NULL) { \
|
|
+ int ret; \
|
|
+ if ((ret = mach64_find_pending_buf_entry(dev_priv, &_entry, _buf))) { \
|
|
+ DRM_ERROR( "couldn't find pending buf %d\n", \
|
|
+ _buf->idx ); \
|
|
+ return ret; \
|
|
+ } \
|
|
+ } \
|
|
+ _entry->discard = 1; \
|
|
+ } while(0)
|
|
+
|
|
+#define DMAADVANCEHOSTDATA( dev_priv ) \
|
|
+ do { \
|
|
+ struct list_head *ptr; \
|
|
+ int ret; \
|
|
+ \
|
|
+ if ( MACH64_VERBOSE ) { \
|
|
+ DRM_INFO( "DMAADVANCEHOSTDATA() in \n" ); \
|
|
+ } \
|
|
+ \
|
|
+ if (_buf->used <= 0) { \
|
|
+ DRM_ERROR( "DMAADVANCEHOSTDATA(): sending empty buf %d\n", _buf->idx ); \
|
|
+ return -EFAULT; \
|
|
+ } \
|
|
+ if (list_empty(&dev_priv->placeholders)) { \
|
|
+ DRM_ERROR( "empty placeholder list in DMAADVANCEHOSTDATA()\n" ); \
|
|
+ return -EFAULT; \
|
|
+ } \
|
|
+ \
|
|
+ ptr = dev_priv->placeholders.next; \
|
|
+ list_del(ptr); \
|
|
+ _entry = list_entry(ptr, drm_mach64_freelist_t, list); \
|
|
+ _entry->buf = _buf; \
|
|
+ _entry->buf->pending = 1; \
|
|
+ list_add_tail(ptr, &dev_priv->pending); \
|
|
+ _entry->discard = 1; \
|
|
+ if ((ret = mach64_add_hostdata_buf_to_ring( dev_priv, _entry ))) \
|
|
+ return ret; \
|
|
+ } while (0)
|
|
+
|
|
+#endif /* __MACH64_DRV_H__ */
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/mach64/mach64_irq.c
|
|
@@ -0,0 +1,159 @@
|
|
+/* mach64_irq.c -- IRQ handling for ATI Mach64 -*- linux-c -*-
|
|
+ * Created: Tue Feb 25, 2003 by Leif Delgass, based on radeon_irq.c/r128_irq.c
|
|
+ */
|
|
+/*-
|
|
+ * Copyright (C) The Weather Channel, Inc. 2002.
|
|
+ * Copyright 2003 Leif Delgass
|
|
+ * 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
|
|
+ * THE COPYRIGHT OWNER(S) 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>
|
|
+ * Leif Delgass <ldelgass@retinalburn.net>
|
|
+ */
|
|
+
|
|
+#include "drmP.h"
|
|
+#include "drm.h"
|
|
+#include "mach64_drm.h"
|
|
+#include "mach64_drv.h"
|
|
+
|
|
+irqreturn_t mach64_driver_irq_handler(DRM_IRQ_ARGS)
|
|
+{
|
|
+ struct drm_device *dev = arg;
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+ int status;
|
|
+
|
|
+ status = MACH64_READ(MACH64_CRTC_INT_CNTL);
|
|
+
|
|
+ /* VBLANK interrupt */
|
|
+ if (status & MACH64_CRTC_VBLANK_INT) {
|
|
+ /* Mask off all interrupt ack bits before setting the ack bit, since
|
|
+ * there may be other handlers outside the DRM.
|
|
+ *
|
|
+ * NOTE: On mach64, you need to keep the enable bits set when doing
|
|
+ * the ack, despite what the docs say about not acking and enabling
|
|
+ * in a single write.
|
|
+ */
|
|
+ MACH64_WRITE(MACH64_CRTC_INT_CNTL,
|
|
+ (status & ~MACH64_CRTC_INT_ACKS)
|
|
+ | MACH64_CRTC_VBLANK_INT);
|
|
+
|
|
+ atomic_inc(&dev_priv->vbl_received);
|
|
+ drm_handle_vblank(dev, 0);
|
|
+ return IRQ_HANDLED;
|
|
+ }
|
|
+ return IRQ_NONE;
|
|
+}
|
|
+
|
|
+u32 mach64_get_vblank_counter(struct drm_device * dev, int crtc)
|
|
+{
|
|
+ const drm_mach64_private_t *const dev_priv = dev->dev_private;
|
|
+
|
|
+ if (crtc != 0)
|
|
+ return 0;
|
|
+
|
|
+ return atomic_read(&dev_priv->vbl_received);
|
|
+}
|
|
+
|
|
+int mach64_enable_vblank(struct drm_device * dev, int crtc)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+ u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
|
|
+
|
|
+ if (crtc != 0) {
|
|
+ DRM_ERROR("tried to enable vblank on non-existent crtc %d\n",
|
|
+ crtc);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ DRM_DEBUG("before enable vblank CRTC_INT_CTNL: 0x%08x\n", status);
|
|
+
|
|
+ /* Turn on VBLANK interrupt */
|
|
+ MACH64_WRITE(MACH64_CRTC_INT_CNTL, MACH64_READ(MACH64_CRTC_INT_CNTL)
|
|
+ | MACH64_CRTC_VBLANK_INT_EN);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void mach64_disable_vblank(struct drm_device * dev, int crtc)
|
|
+{
|
|
+ if (crtc != 0) {
|
|
+ DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
|
|
+ crtc);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * FIXME: implement proper interrupt disable by using the vblank
|
|
+ * counter register (if available).
|
|
+ */
|
|
+}
|
|
+
|
|
+static void mach64_disable_vblank_local(struct drm_device * dev, int crtc)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+ u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
|
|
+
|
|
+ if (crtc != 0) {
|
|
+ DRM_ERROR("tried to disable vblank on non-existent crtc %d\n",
|
|
+ crtc);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ DRM_DEBUG("before disable vblank CRTC_INT_CTNL: 0x%08x\n", status);
|
|
+
|
|
+ /* Disable and clear VBLANK interrupt */
|
|
+ MACH64_WRITE(MACH64_CRTC_INT_CNTL, (status & ~MACH64_CRTC_VBLANK_INT_EN)
|
|
+ | MACH64_CRTC_VBLANK_INT);
|
|
+}
|
|
+
|
|
+void mach64_driver_irq_preinstall(struct drm_device * dev)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+
|
|
+ u32 status = MACH64_READ(MACH64_CRTC_INT_CNTL);
|
|
+
|
|
+ DRM_DEBUG("before install CRTC_INT_CTNL: 0x%08x\n", status);
|
|
+
|
|
+ mach64_disable_vblank_local(dev, 0);
|
|
+}
|
|
+
|
|
+int mach64_driver_irq_postinstall(struct drm_device * dev)
|
|
+{
|
|
+ return drm_vblank_init(dev, 1);
|
|
+}
|
|
+
|
|
+void mach64_driver_irq_uninstall(struct drm_device * dev)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+ if (!dev_priv)
|
|
+ return;
|
|
+
|
|
+ mach64_disable_vblank_local(dev, 0);
|
|
+
|
|
+ DRM_DEBUG("after uninstall CRTC_INT_CTNL: 0x%08x\n",
|
|
+ MACH64_READ(MACH64_CRTC_INT_CNTL));
|
|
+}
|
|
--- /dev/null
|
|
+++ b/drivers/gpu/drm/mach64/mach64_state.c
|
|
@@ -0,0 +1,910 @@
|
|
+/* mach64_state.c -- State support for mach64 (Rage Pro) driver -*- linux-c -*-
|
|
+ * Created: Sun Dec 03 19:20:26 2000 by gareth@valinux.com
|
|
+ */
|
|
+/*
|
|
+ * Copyright 2000 Gareth Hughes
|
|
+ * Copyright 2002-2003 Leif Delgass
|
|
+ * 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 COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Gareth Hughes <gareth@valinux.com>
|
|
+ * Leif Delgass <ldelgass@retinalburn.net>
|
|
+ * José Fonseca <j_r_fonseca@yahoo.co.uk>
|
|
+ */
|
|
+
|
|
+#include "drmP.h"
|
|
+#include "drm.h"
|
|
+#include "mach64_drm.h"
|
|
+#include "mach64_drv.h"
|
|
+
|
|
+/* Interface history:
|
|
+ *
|
|
+ * 1.0 - Initial mach64 DRM
|
|
+ *
|
|
+ */
|
|
+struct drm_ioctl_desc mach64_ioctls[] = {
|
|
+ DRM_IOCTL_DEF(DRM_MACH64_INIT, mach64_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
|
|
+ DRM_IOCTL_DEF(DRM_MACH64_CLEAR, mach64_dma_clear, DRM_AUTH),
|
|
+ DRM_IOCTL_DEF(DRM_MACH64_SWAP, mach64_dma_swap, DRM_AUTH),
|
|
+ DRM_IOCTL_DEF(DRM_MACH64_IDLE, mach64_dma_idle, DRM_AUTH),
|
|
+ DRM_IOCTL_DEF(DRM_MACH64_RESET, mach64_engine_reset, DRM_AUTH),
|
|
+ DRM_IOCTL_DEF(DRM_MACH64_VERTEX, mach64_dma_vertex, DRM_AUTH),
|
|
+ DRM_IOCTL_DEF(DRM_MACH64_BLIT, mach64_dma_blit, DRM_AUTH),
|
|
+ DRM_IOCTL_DEF(DRM_MACH64_FLUSH, mach64_dma_flush, DRM_AUTH),
|
|
+ DRM_IOCTL_DEF(DRM_MACH64_GETPARAM, mach64_get_param, DRM_AUTH),
|
|
+};
|
|
+
|
|
+int mach64_max_ioctl = DRM_ARRAY_SIZE(mach64_ioctls);
|
|
+
|
|
+/* ================================================================
|
|
+ * DMA hardware state programming functions
|
|
+ */
|
|
+
|
|
+static void mach64_print_dirty(const char *msg, unsigned int flags)
|
|
+{
|
|
+ DRM_DEBUG("%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s\n",
|
|
+ msg,
|
|
+ flags,
|
|
+ (flags & MACH64_UPLOAD_DST_OFF_PITCH) ? "dst_off_pitch, " :
|
|
+ "",
|
|
+ (flags & MACH64_UPLOAD_Z_ALPHA_CNTL) ? "z_alpha_cntl, " : "",
|
|
+ (flags & MACH64_UPLOAD_SCALE_3D_CNTL) ? "scale_3d_cntl, " :
|
|
+ "", (flags & MACH64_UPLOAD_DP_FOG_CLR) ? "dp_fog_clr, " : "",
|
|
+ (flags & MACH64_UPLOAD_DP_WRITE_MASK) ? "dp_write_mask, " :
|
|
+ "",
|
|
+ (flags & MACH64_UPLOAD_DP_PIX_WIDTH) ? "dp_pix_width, " : "",
|
|
+ (flags & MACH64_UPLOAD_SETUP_CNTL) ? "setup_cntl, " : "",
|
|
+ (flags & MACH64_UPLOAD_MISC) ? "misc, " : "",
|
|
+ (flags & MACH64_UPLOAD_TEXTURE) ? "texture, " : "",
|
|
+ (flags & MACH64_UPLOAD_TEX0IMAGE) ? "tex0 image, " : "",
|
|
+ (flags & MACH64_UPLOAD_TEX1IMAGE) ? "tex1 image, " : "",
|
|
+ (flags & MACH64_UPLOAD_CLIPRECTS) ? "cliprects, " : "");
|
|
+}
|
|
+
|
|
+/* Mach64 doesn't have hardware cliprects, just one hardware scissor,
|
|
+ * so the GL scissor is intersected with each cliprect here
|
|
+ */
|
|
+/* This function returns 0 on success, 1 for no intersection, and
|
|
+ * negative for an error
|
|
+ */
|
|
+static int mach64_emit_cliprect(struct drm_file *file_priv,
|
|
+ drm_mach64_private_t * dev_priv,
|
|
+ struct drm_clip_rect * box)
|
|
+{
|
|
+ u32 sc_left_right, sc_top_bottom;
|
|
+ struct drm_clip_rect scissor;
|
|
+ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
|
|
+ drm_mach64_context_regs_t *regs = &sarea_priv->context_state;
|
|
+ DMALOCALS;
|
|
+
|
|
+ DRM_DEBUG("box=%p\n", box);
|
|
+
|
|
+ /* Get GL scissor */
|
|
+ /* FIXME: store scissor in SAREA as a cliprect instead of in
|
|
+ * hardware format, or do intersection client-side
|
|
+ */
|
|
+ scissor.x1 = regs->sc_left_right & 0xffff;
|
|
+ scissor.x2 = (regs->sc_left_right & 0xffff0000) >> 16;
|
|
+ scissor.y1 = regs->sc_top_bottom & 0xffff;
|
|
+ scissor.y2 = (regs->sc_top_bottom & 0xffff0000) >> 16;
|
|
+
|
|
+ /* Intersect GL scissor with cliprect */
|
|
+ if (box->x1 > scissor.x1)
|
|
+ scissor.x1 = box->x1;
|
|
+ if (box->y1 > scissor.y1)
|
|
+ scissor.y1 = box->y1;
|
|
+ if (box->x2 < scissor.x2)
|
|
+ scissor.x2 = box->x2;
|
|
+ if (box->y2 < scissor.y2)
|
|
+ scissor.y2 = box->y2;
|
|
+ /* positive return means skip */
|
|
+ if (scissor.x1 >= scissor.x2)
|
|
+ return 1;
|
|
+ if (scissor.y1 >= scissor.y2)
|
|
+ return 1;
|
|
+
|
|
+ DMAGETPTR(file_priv, dev_priv, 2); /* returns on failure to get buffer */
|
|
+
|
|
+ sc_left_right = ((scissor.x1 << 0) | (scissor.x2 << 16));
|
|
+ sc_top_bottom = ((scissor.y1 << 0) | (scissor.y2 << 16));
|
|
+
|
|
+ DMAOUTREG(MACH64_SC_LEFT_RIGHT, sc_left_right);
|
|
+ DMAOUTREG(MACH64_SC_TOP_BOTTOM, sc_top_bottom);
|
|
+
|
|
+ DMAADVANCE(dev_priv, 1);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static __inline__ int mach64_emit_state(struct drm_file *file_priv,
|
|
+ drm_mach64_private_t * dev_priv)
|
|
+{
|
|
+ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
|
|
+ drm_mach64_context_regs_t *regs = &sarea_priv->context_state;
|
|
+ unsigned int dirty = sarea_priv->dirty;
|
|
+ u32 offset = ((regs->tex_size_pitch & 0xf0) >> 2);
|
|
+ DMALOCALS;
|
|
+
|
|
+ if (MACH64_VERBOSE) {
|
|
+ mach64_print_dirty(__FUNCTION__, dirty);
|
|
+ } else {
|
|
+ DRM_DEBUG("dirty=0x%08x\n", dirty);
|
|
+ }
|
|
+
|
|
+ DMAGETPTR(file_priv, dev_priv, 17); /* returns on failure to get buffer */
|
|
+
|
|
+ if (dirty & MACH64_UPLOAD_MISC) {
|
|
+ DMAOUTREG(MACH64_DP_MIX, regs->dp_mix);
|
|
+ DMAOUTREG(MACH64_DP_SRC, regs->dp_src);
|
|
+ DMAOUTREG(MACH64_CLR_CMP_CNTL, regs->clr_cmp_cntl);
|
|
+ DMAOUTREG(MACH64_GUI_TRAJ_CNTL, regs->gui_traj_cntl);
|
|
+ sarea_priv->dirty &= ~MACH64_UPLOAD_MISC;
|
|
+ }
|
|
+
|
|
+ if (dirty & MACH64_UPLOAD_DST_OFF_PITCH) {
|
|
+ DMAOUTREG(MACH64_DST_OFF_PITCH, regs->dst_off_pitch);
|
|
+ sarea_priv->dirty &= ~MACH64_UPLOAD_DST_OFF_PITCH;
|
|
+ }
|
|
+ if (dirty & MACH64_UPLOAD_Z_OFF_PITCH) {
|
|
+ DMAOUTREG(MACH64_Z_OFF_PITCH, regs->z_off_pitch);
|
|
+ sarea_priv->dirty &= ~MACH64_UPLOAD_Z_OFF_PITCH;
|
|
+ }
|
|
+ if (dirty & MACH64_UPLOAD_Z_ALPHA_CNTL) {
|
|
+ DMAOUTREG(MACH64_Z_CNTL, regs->z_cntl);
|
|
+ DMAOUTREG(MACH64_ALPHA_TST_CNTL, regs->alpha_tst_cntl);
|
|
+ sarea_priv->dirty &= ~MACH64_UPLOAD_Z_ALPHA_CNTL;
|
|
+ }
|
|
+ if (dirty & MACH64_UPLOAD_SCALE_3D_CNTL) {
|
|
+ DMAOUTREG(MACH64_SCALE_3D_CNTL, regs->scale_3d_cntl);
|
|
+ sarea_priv->dirty &= ~MACH64_UPLOAD_SCALE_3D_CNTL;
|
|
+ }
|
|
+ if (dirty & MACH64_UPLOAD_DP_FOG_CLR) {
|
|
+ DMAOUTREG(MACH64_DP_FOG_CLR, regs->dp_fog_clr);
|
|
+ sarea_priv->dirty &= ~MACH64_UPLOAD_DP_FOG_CLR;
|
|
+ }
|
|
+ if (dirty & MACH64_UPLOAD_DP_WRITE_MASK) {
|
|
+ DMAOUTREG(MACH64_DP_WRITE_MASK, regs->dp_write_mask);
|
|
+ sarea_priv->dirty &= ~MACH64_UPLOAD_DP_WRITE_MASK;
|
|
+ }
|
|
+ if (dirty & MACH64_UPLOAD_DP_PIX_WIDTH) {
|
|
+ DMAOUTREG(MACH64_DP_PIX_WIDTH, regs->dp_pix_width);
|
|
+ sarea_priv->dirty &= ~MACH64_UPLOAD_DP_PIX_WIDTH;
|
|
+ }
|
|
+ if (dirty & MACH64_UPLOAD_SETUP_CNTL) {
|
|
+ DMAOUTREG(MACH64_SETUP_CNTL, regs->setup_cntl);
|
|
+ sarea_priv->dirty &= ~MACH64_UPLOAD_SETUP_CNTL;
|
|
+ }
|
|
+
|
|
+ if (dirty & MACH64_UPLOAD_TEXTURE) {
|
|
+ DMAOUTREG(MACH64_TEX_SIZE_PITCH, regs->tex_size_pitch);
|
|
+ DMAOUTREG(MACH64_TEX_CNTL, regs->tex_cntl);
|
|
+ DMAOUTREG(MACH64_SECONDARY_TEX_OFF, regs->secondary_tex_off);
|
|
+ DMAOUTREG(MACH64_TEX_0_OFF + offset, regs->tex_offset);
|
|
+ sarea_priv->dirty &= ~MACH64_UPLOAD_TEXTURE;
|
|
+ }
|
|
+
|
|
+ DMAADVANCE(dev_priv, 1);
|
|
+
|
|
+ sarea_priv->dirty &= MACH64_UPLOAD_CLIPRECTS;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+}
|
|
+
|
|
+/* ================================================================
|
|
+ * DMA command dispatch functions
|
|
+ */
|
|
+
|
|
+static int mach64_dma_dispatch_clear(struct drm_device * dev,
|
|
+ struct drm_file *file_priv,
|
|
+ unsigned int flags,
|
|
+ int cx, int cy, int cw, int ch,
|
|
+ unsigned int clear_color,
|
|
+ unsigned int clear_depth)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
|
|
+ drm_mach64_context_regs_t *ctx = &sarea_priv->context_state;
|
|
+ int nbox = sarea_priv->nbox;
|
|
+ struct drm_clip_rect *pbox = sarea_priv->boxes;
|
|
+ u32 fb_bpp, depth_bpp;
|
|
+ int i;
|
|
+ DMALOCALS;
|
|
+
|
|
+ DRM_DEBUG("\n");
|
|
+
|
|
+ switch (dev_priv->fb_bpp) {
|
|
+ case 16:
|
|
+ fb_bpp = MACH64_DATATYPE_RGB565;
|
|
+ break;
|
|
+ case 32:
|
|
+ fb_bpp = MACH64_DATATYPE_ARGB8888;
|
|
+ break;
|
|
+ default:
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ switch (dev_priv->depth_bpp) {
|
|
+ case 16:
|
|
+ depth_bpp = MACH64_DATATYPE_RGB565;
|
|
+ break;
|
|
+ case 24:
|
|
+ case 32:
|
|
+ depth_bpp = MACH64_DATATYPE_ARGB8888;
|
|
+ break;
|
|
+ default:
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (!nbox)
|
|
+ return 0;
|
|
+
|
|
+ DMAGETPTR(file_priv, dev_priv, nbox * 31); /* returns on failure to get buffer */
|
|
+
|
|
+ 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 & (MACH64_FRONT | MACH64_BACK)) {
|
|
+ /* Setup for color buffer clears
|
|
+ */
|
|
+
|
|
+ DMAOUTREG(MACH64_Z_CNTL, 0);
|
|
+ DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
|
|
+
|
|
+ DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right);
|
|
+ DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom);
|
|
+
|
|
+ DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
|
|
+ DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
|
|
+ (MACH64_DST_X_LEFT_TO_RIGHT |
|
|
+ MACH64_DST_Y_TOP_TO_BOTTOM));
|
|
+
|
|
+ DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) |
|
|
+ (fb_bpp << 4) |
|
|
+ (fb_bpp << 8) |
|
|
+ (fb_bpp << 16) |
|
|
+ (fb_bpp << 28)));
|
|
+
|
|
+ DMAOUTREG(MACH64_DP_FRGD_CLR, clear_color);
|
|
+ DMAOUTREG(MACH64_DP_WRITE_MASK, ctx->dp_write_mask);
|
|
+ DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D |
|
|
+ MACH64_FRGD_MIX_S));
|
|
+ DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR |
|
|
+ MACH64_FRGD_SRC_FRGD_CLR |
|
|
+ MACH64_MONO_SRC_ONE));
|
|
+
|
|
+ }
|
|
+
|
|
+ if (flags & MACH64_FRONT) {
|
|
+
|
|
+ DMAOUTREG(MACH64_DST_OFF_PITCH,
|
|
+ dev_priv->front_offset_pitch);
|
|
+ DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
|
|
+ DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
|
|
+
|
|
+ }
|
|
+
|
|
+ if (flags & MACH64_BACK) {
|
|
+
|
|
+ DMAOUTREG(MACH64_DST_OFF_PITCH,
|
|
+ dev_priv->back_offset_pitch);
|
|
+ DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
|
|
+ DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
|
|
+
|
|
+ }
|
|
+
|
|
+ if (flags & MACH64_DEPTH) {
|
|
+ /* Setup for depth buffer clear
|
|
+ */
|
|
+ DMAOUTREG(MACH64_Z_CNTL, 0);
|
|
+ DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
|
|
+
|
|
+ DMAOUTREG(MACH64_SC_LEFT_RIGHT, ctx->sc_left_right);
|
|
+ DMAOUTREG(MACH64_SC_TOP_BOTTOM, ctx->sc_top_bottom);
|
|
+
|
|
+ DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
|
|
+ DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
|
|
+ (MACH64_DST_X_LEFT_TO_RIGHT |
|
|
+ MACH64_DST_Y_TOP_TO_BOTTOM));
|
|
+
|
|
+ DMAOUTREG(MACH64_DP_PIX_WIDTH, ((depth_bpp << 0) |
|
|
+ (depth_bpp << 4) |
|
|
+ (depth_bpp << 8) |
|
|
+ (depth_bpp << 16) |
|
|
+ (depth_bpp << 28)));
|
|
+
|
|
+ DMAOUTREG(MACH64_DP_FRGD_CLR, clear_depth);
|
|
+ DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);
|
|
+ DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D |
|
|
+ MACH64_FRGD_MIX_S));
|
|
+ DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_FRGD_CLR |
|
|
+ MACH64_FRGD_SRC_FRGD_CLR |
|
|
+ MACH64_MONO_SRC_ONE));
|
|
+
|
|
+ DMAOUTREG(MACH64_DST_OFF_PITCH,
|
|
+ dev_priv->depth_offset_pitch);
|
|
+ DMAOUTREG(MACH64_DST_X_Y, (y << 16) | x);
|
|
+ DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ DMAADVANCE(dev_priv, 1);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mach64_dma_dispatch_swap(struct drm_device * dev,
|
|
+ struct drm_file *file_priv)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
|
|
+ int nbox = sarea_priv->nbox;
|
|
+ struct drm_clip_rect *pbox = sarea_priv->boxes;
|
|
+ u32 fb_bpp;
|
|
+ int i;
|
|
+ DMALOCALS;
|
|
+
|
|
+ DRM_DEBUG("\n");
|
|
+
|
|
+ switch (dev_priv->fb_bpp) {
|
|
+ case 16:
|
|
+ fb_bpp = MACH64_DATATYPE_RGB565;
|
|
+ break;
|
|
+ case 32:
|
|
+ default:
|
|
+ fb_bpp = MACH64_DATATYPE_ARGB8888;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (!nbox)
|
|
+ return 0;
|
|
+
|
|
+ DMAGETPTR(file_priv, dev_priv, 13 + nbox * 4); /* returns on failure to get buffer */
|
|
+
|
|
+ DMAOUTREG(MACH64_Z_CNTL, 0);
|
|
+ DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
|
|
+
|
|
+ DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16)); /* no scissor */
|
|
+ DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16));
|
|
+
|
|
+ DMAOUTREG(MACH64_CLR_CMP_CNTL, 0);
|
|
+ DMAOUTREG(MACH64_GUI_TRAJ_CNTL, (MACH64_DST_X_LEFT_TO_RIGHT |
|
|
+ MACH64_DST_Y_TOP_TO_BOTTOM));
|
|
+
|
|
+ DMAOUTREG(MACH64_DP_PIX_WIDTH, ((fb_bpp << 0) |
|
|
+ (fb_bpp << 4) |
|
|
+ (fb_bpp << 8) |
|
|
+ (fb_bpp << 16) | (fb_bpp << 28)));
|
|
+
|
|
+ DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff);
|
|
+ DMAOUTREG(MACH64_DP_MIX, (MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S));
|
|
+ DMAOUTREG(MACH64_DP_SRC, (MACH64_BKGD_SRC_BKGD_CLR |
|
|
+ MACH64_FRGD_SRC_BLIT | MACH64_MONO_SRC_ONE));
|
|
+
|
|
+ DMAOUTREG(MACH64_SRC_OFF_PITCH, dev_priv->back_offset_pitch);
|
|
+ DMAOUTREG(MACH64_DST_OFF_PITCH, dev_priv->front_offset_pitch);
|
|
+
|
|
+ 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 swap %d,%d-%d,%d\n",
|
|
+ pbox[i].x1, pbox[i].y1, pbox[i].x2, pbox[i].y2);
|
|
+
|
|
+ DMAOUTREG(MACH64_SRC_WIDTH1, w);
|
|
+ DMAOUTREG(MACH64_SRC_Y_X, (x << 16) | y);
|
|
+ DMAOUTREG(MACH64_DST_Y_X, (x << 16) | y);
|
|
+ DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (h << 16) | w);
|
|
+
|
|
+ }
|
|
+
|
|
+ DMAADVANCE(dev_priv, 1);
|
|
+
|
|
+ if (dev_priv->driver_mode == MACH64_MODE_DMA_ASYNC) {
|
|
+ for (i = 0; i < MACH64_MAX_QUEUED_FRAMES - 1; i++) {
|
|
+ dev_priv->frame_ofs[i] = dev_priv->frame_ofs[i + 1];
|
|
+ }
|
|
+ dev_priv->frame_ofs[i] = GETRINGOFFSET();
|
|
+
|
|
+ dev_priv->sarea_priv->frames_queued++;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mach64_do_get_frames_queued(drm_mach64_private_t * dev_priv)
|
|
+{
|
|
+ drm_mach64_descriptor_ring_t *ring = &dev_priv->ring;
|
|
+ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
|
|
+ int i, start;
|
|
+ u32 head, tail, ofs;
|
|
+
|
|
+ DRM_DEBUG("\n");
|
|
+
|
|
+ if (sarea_priv->frames_queued == 0)
|
|
+ return 0;
|
|
+
|
|
+ tail = ring->tail;
|
|
+ mach64_ring_tick(dev_priv, ring);
|
|
+ head = ring->head;
|
|
+
|
|
+ start = (MACH64_MAX_QUEUED_FRAMES -
|
|
+ DRM_MIN(MACH64_MAX_QUEUED_FRAMES, sarea_priv->frames_queued));
|
|
+
|
|
+ if (head == tail) {
|
|
+ sarea_priv->frames_queued = 0;
|
|
+ for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) {
|
|
+ dev_priv->frame_ofs[i] = ~0;
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ for (i = start; i < MACH64_MAX_QUEUED_FRAMES; i++) {
|
|
+ ofs = dev_priv->frame_ofs[i];
|
|
+ DRM_DEBUG("frame_ofs[%d] ofs: %d\n", i, ofs);
|
|
+ if (ofs == ~0 ||
|
|
+ (head < tail && (ofs < head || ofs >= tail)) ||
|
|
+ (head > tail && (ofs < head && ofs >= tail))) {
|
|
+ sarea_priv->frames_queued =
|
|
+ (MACH64_MAX_QUEUED_FRAMES - 1) - i;
|
|
+ dev_priv->frame_ofs[i] = ~0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return sarea_priv->frames_queued;
|
|
+}
|
|
+
|
|
+/* Copy and verify a client submited buffer.
|
|
+ * FIXME: Make an assembly optimized version
|
|
+ */
|
|
+static __inline__ int copy_from_user_vertex(u32 *to,
|
|
+ const u32 __user *ufrom,
|
|
+ unsigned long bytes)
|
|
+{
|
|
+ unsigned long n = bytes; /* dwords remaining in buffer */
|
|
+ u32 *from, *orig_from;
|
|
+
|
|
+ from = drm_alloc(bytes, DRM_MEM_DRIVER);
|
|
+ if (from == NULL)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ if (DRM_COPY_FROM_USER(from, ufrom, bytes)) {
|
|
+ drm_free(from, bytes, DRM_MEM_DRIVER);
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ orig_from = from; /* we'll be modifying the "from" ptr, so save it */
|
|
+
|
|
+ n >>= 2;
|
|
+
|
|
+ while (n > 1) {
|
|
+ u32 data, reg, count;
|
|
+
|
|
+ data = *from++;
|
|
+
|
|
+ n--;
|
|
+
|
|
+ reg = le32_to_cpu(data);
|
|
+ count = (reg >> 16) + 1;
|
|
+ if (count <= n) {
|
|
+ n -= count;
|
|
+ reg &= 0xffff;
|
|
+
|
|
+ /* This is an exact match of Mach64's Setup Engine registers,
|
|
+ * excluding SETUP_CNTL (1_C1).
|
|
+ */
|
|
+ if ((reg >= 0x0190 && reg < 0x01c1) ||
|
|
+ (reg >= 0x01ca && reg <= 0x01cf)) {
|
|
+ *to++ = data;
|
|
+ memcpy(to, from, count << 2);
|
|
+ from += count;
|
|
+ to += count;
|
|
+ } else {
|
|
+ DRM_ERROR("Got bad command: 0x%04x\n", reg);
|
|
+ drm_free(orig_from, bytes, DRM_MEM_DRIVER);
|
|
+ return -EACCES;
|
|
+ }
|
|
+ } else {
|
|
+ DRM_ERROR
|
|
+ ("Got bad command count(=%u) dwords remaining=%lu\n",
|
|
+ count, n);
|
|
+ drm_free(orig_from, bytes, DRM_MEM_DRIVER);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ drm_free(orig_from, bytes, DRM_MEM_DRIVER);
|
|
+ if (n == 0)
|
|
+ return 0;
|
|
+ else {
|
|
+ DRM_ERROR("Bad buf->used(=%lu)\n", bytes);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int mach64_dma_dispatch_vertex(struct drm_device * dev,
|
|
+ struct drm_file *file_priv,
|
|
+ drm_mach64_vertex_t * vertex)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
|
|
+ struct drm_buf *copy_buf;
|
|
+ void *buf = vertex->buf;
|
|
+ unsigned long used = vertex->used;
|
|
+ int ret = 0;
|
|
+ int i = 0;
|
|
+ int done = 0;
|
|
+ int verify_ret = 0;
|
|
+ DMALOCALS;
|
|
+
|
|
+ DRM_DEBUG("buf=%p used=%lu nbox=%d\n",
|
|
+ buf, used, sarea_priv->nbox);
|
|
+
|
|
+ if (!used)
|
|
+ goto _vertex_done;
|
|
+
|
|
+ copy_buf = mach64_freelist_get(dev_priv);
|
|
+ if (copy_buf == NULL) {
|
|
+ DRM_ERROR("couldn't get buffer\n");
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+
|
|
+ /* Mach64's vertex data is actually register writes. To avoid security
|
|
+ * compromises these register writes have to be verified and copied from
|
|
+ * user space into a private DMA buffer.
|
|
+ */
|
|
+ verify_ret = copy_from_user_vertex(GETBUFPTR(copy_buf), buf, used);
|
|
+
|
|
+ if (verify_ret != 0) {
|
|
+ mach64_freelist_put(dev_priv, copy_buf);
|
|
+ goto _vertex_done;
|
|
+ }
|
|
+
|
|
+ copy_buf->used = used;
|
|
+
|
|
+ DMASETPTR(copy_buf);
|
|
+
|
|
+ if (sarea_priv->dirty & ~MACH64_UPLOAD_CLIPRECTS) {
|
|
+ ret = mach64_emit_state(file_priv, dev_priv);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ do {
|
|
+ /* Emit the next cliprect */
|
|
+ if (i < sarea_priv->nbox) {
|
|
+ ret = mach64_emit_cliprect(file_priv, dev_priv,
|
|
+ &sarea_priv->boxes[i]);
|
|
+ if (ret < 0) {
|
|
+ /* failed to get buffer */
|
|
+ return ret;
|
|
+ } else if (ret != 0) {
|
|
+ /* null intersection with scissor */
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ if ((i >= sarea_priv->nbox - 1))
|
|
+ done = 1;
|
|
+
|
|
+ /* Add the buffer to the DMA queue */
|
|
+ DMAADVANCE(dev_priv, done);
|
|
+
|
|
+ } while (++i < sarea_priv->nbox);
|
|
+
|
|
+ if (!done) {
|
|
+ if (copy_buf->pending) {
|
|
+ DMADISCARDBUF();
|
|
+ } else {
|
|
+ /* This buffer wasn't used (no cliprects), so place it
|
|
+ * back on the free list
|
|
+ */
|
|
+ mach64_freelist_put(dev_priv, copy_buf);
|
|
+ }
|
|
+ }
|
|
+
|
|
+_vertex_done:
|
|
+ sarea_priv->dirty &= ~MACH64_UPLOAD_CLIPRECTS;
|
|
+ sarea_priv->nbox = 0;
|
|
+
|
|
+ return verify_ret;
|
|
+}
|
|
+
|
|
+static __inline__ int copy_from_user_blit(u32 *to,
|
|
+ const u32 __user *ufrom,
|
|
+ unsigned long bytes)
|
|
+{
|
|
+ to = (u32 *)((char *)to + MACH64_HOSTDATA_BLIT_OFFSET);
|
|
+
|
|
+ if (DRM_COPY_FROM_USER(to, ufrom, bytes)) {
|
|
+ return -EFAULT;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mach64_dma_dispatch_blit(struct drm_device * dev,
|
|
+ struct drm_file *file_priv,
|
|
+ drm_mach64_blit_t * blit)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+ int dword_shift, dwords;
|
|
+ unsigned long used;
|
|
+ struct drm_buf *copy_buf;
|
|
+ int verify_ret = 0;
|
|
+ DMALOCALS;
|
|
+
|
|
+ /* 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 MACH64_DATATYPE_ARGB8888:
|
|
+ dword_shift = 0;
|
|
+ break;
|
|
+ case MACH64_DATATYPE_ARGB1555:
|
|
+ case MACH64_DATATYPE_RGB565:
|
|
+ case MACH64_DATATYPE_VYUY422:
|
|
+ case MACH64_DATATYPE_YVYU422:
|
|
+ case MACH64_DATATYPE_ARGB4444:
|
|
+ dword_shift = 1;
|
|
+ break;
|
|
+ case MACH64_DATATYPE_CI8:
|
|
+ case MACH64_DATATYPE_RGB8:
|
|
+ dword_shift = 2;
|
|
+ break;
|
|
+ default:
|
|
+ DRM_ERROR("invalid blit format %d\n", blit->format);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* Set buf->used to the bytes of blit data based on the blit dimensions
|
|
+ * and verify the size. When the setup is emitted to the buffer with
|
|
+ * the DMA* macros below, buf->used is incremented to include the bytes
|
|
+ * used for setup as well as the blit data.
|
|
+ */
|
|
+ dwords = (blit->width * blit->height) >> dword_shift;
|
|
+ used = dwords << 2;
|
|
+ if (used <= 0 ||
|
|
+ used > MACH64_BUFFER_SIZE - MACH64_HOSTDATA_BLIT_OFFSET) {
|
|
+ DRM_ERROR("Invalid blit size: %lu bytes\n", used);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ copy_buf = mach64_freelist_get(dev_priv);
|
|
+ if (copy_buf == NULL) {
|
|
+ DRM_ERROR("couldn't get buffer\n");
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+
|
|
+ /* Copy the blit data from userspace.
|
|
+ *
|
|
+ * XXX: This is overkill. The most efficient solution would be having
|
|
+ * two sets of buffers (one set private for vertex data, the other set
|
|
+ * client-writable for blits). However that would bring more complexity
|
|
+ * and would break backward compatability. The solution currently
|
|
+ * implemented is keeping all buffers private, allowing to secure the
|
|
+ * driver, without increasing complexity at the expense of some speed
|
|
+ * transfering data.
|
|
+ */
|
|
+ verify_ret = copy_from_user_blit(GETBUFPTR(copy_buf), blit->buf, used);
|
|
+
|
|
+ if (verify_ret != 0) {
|
|
+ mach64_freelist_put(dev_priv, copy_buf);
|
|
+ goto _blit_done;
|
|
+ }
|
|
+
|
|
+ copy_buf->used = used;
|
|
+
|
|
+ /* FIXME: Use a last buffer flag and reduce the state emitted for subsequent,
|
|
+ * continuation buffers?
|
|
+ */
|
|
+
|
|
+ /* Blit via BM_HOSTDATA (gui-master) - like HOST_DATA[0-15], but doesn't require
|
|
+ * a register command every 16 dwords. State setup is added at the start of the
|
|
+ * buffer -- the client leaves space for this based on MACH64_HOSTDATA_BLIT_OFFSET
|
|
+ */
|
|
+ DMASETPTR(copy_buf);
|
|
+
|
|
+ DMAOUTREG(MACH64_Z_CNTL, 0);
|
|
+ DMAOUTREG(MACH64_SCALE_3D_CNTL, 0);
|
|
+
|
|
+ DMAOUTREG(MACH64_SC_LEFT_RIGHT, 0 | (8191 << 16)); /* no scissor */
|
|
+ DMAOUTREG(MACH64_SC_TOP_BOTTOM, 0 | (16383 << 16));
|
|
+
|
|
+ DMAOUTREG(MACH64_CLR_CMP_CNTL, 0); /* disable */
|
|
+ DMAOUTREG(MACH64_GUI_TRAJ_CNTL,
|
|
+ MACH64_DST_X_LEFT_TO_RIGHT | MACH64_DST_Y_TOP_TO_BOTTOM);
|
|
+
|
|
+ DMAOUTREG(MACH64_DP_PIX_WIDTH, (blit->format << 0) /* dst pix width */
|
|
+ |(blit->format << 4) /* composite pix width */
|
|
+ |(blit->format << 8) /* src pix width */
|
|
+ |(blit->format << 16) /* host data pix width */
|
|
+ |(blit->format << 28) /* scaler/3D pix width */
|
|
+ );
|
|
+
|
|
+ DMAOUTREG(MACH64_DP_WRITE_MASK, 0xffffffff); /* enable all planes */
|
|
+ DMAOUTREG(MACH64_DP_MIX, MACH64_BKGD_MIX_D | MACH64_FRGD_MIX_S);
|
|
+ DMAOUTREG(MACH64_DP_SRC,
|
|
+ MACH64_BKGD_SRC_BKGD_CLR
|
|
+ | MACH64_FRGD_SRC_HOST | MACH64_MONO_SRC_ONE);
|
|
+
|
|
+ DMAOUTREG(MACH64_DST_OFF_PITCH,
|
|
+ (blit->pitch << 22) | (blit->offset >> 3));
|
|
+ DMAOUTREG(MACH64_DST_X_Y, (blit->y << 16) | blit->x);
|
|
+ DMAOUTREG(MACH64_DST_WIDTH_HEIGHT, (blit->height << 16) | blit->width);
|
|
+
|
|
+ DRM_DEBUG("%lu bytes\n", used);
|
|
+
|
|
+ /* Add the buffer to the queue */
|
|
+ DMAADVANCEHOSTDATA(dev_priv);
|
|
+
|
|
+_blit_done:
|
|
+ return verify_ret;
|
|
+}
|
|
+
|
|
+/* ================================================================
|
|
+ * IOCTL functions
|
|
+ */
|
|
+
|
|
+int mach64_dma_clear(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
|
|
+ drm_mach64_clear_t *clear = data;
|
|
+ int ret;
|
|
+
|
|
+ DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
|
|
+
|
|
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
|
|
+
|
|
+ if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
|
|
+ sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
|
|
+
|
|
+ ret = mach64_dma_dispatch_clear(dev, file_priv, clear->flags,
|
|
+ clear->x, clear->y, clear->w, clear->h,
|
|
+ clear->clear_color,
|
|
+ clear->clear_depth);
|
|
+
|
|
+ /* Make sure we restore the 3D state next time.
|
|
+ */
|
|
+ sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int mach64_dma_swap(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
|
|
+ int ret;
|
|
+
|
|
+ DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
|
|
+
|
|
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
|
|
+
|
|
+ if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
|
|
+ sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
|
|
+
|
|
+ ret = mach64_dma_dispatch_swap(dev, file_priv);
|
|
+
|
|
+ /* Make sure we restore the 3D state next time.
|
|
+ */
|
|
+ sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int mach64_dma_vertex(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
|
|
+ drm_mach64_vertex_t *vertex = data;
|
|
+
|
|
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
|
|
+
|
|
+ if (!dev_priv) {
|
|
+ DRM_ERROR("called with no initialization\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ DRM_DEBUG("pid=%d buf=%p used=%lu discard=%d\n",
|
|
+ DRM_CURRENTPID,
|
|
+ vertex->buf, vertex->used, vertex->discard);
|
|
+
|
|
+ if (vertex->prim < 0 || vertex->prim > MACH64_PRIM_POLYGON) {
|
|
+ DRM_ERROR("buffer prim %d\n", vertex->prim);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (vertex->used > MACH64_BUFFER_SIZE || (vertex->used & 3) != 0) {
|
|
+ DRM_ERROR("Invalid vertex buffer size: %lu bytes\n",
|
|
+ vertex->used);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (sarea_priv->nbox > MACH64_NR_SAREA_CLIPRECTS)
|
|
+ sarea_priv->nbox = MACH64_NR_SAREA_CLIPRECTS;
|
|
+
|
|
+ return mach64_dma_dispatch_vertex(dev, file_priv, vertex);
|
|
+}
|
|
+
|
|
+int mach64_dma_blit(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+ drm_mach64_sarea_t *sarea_priv = dev_priv->sarea_priv;
|
|
+ drm_mach64_blit_t *blit = data;
|
|
+ int ret;
|
|
+
|
|
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
|
|
+
|
|
+ ret = mach64_dma_dispatch_blit(dev, file_priv, blit);
|
|
+
|
|
+ /* Make sure we restore the 3D state next time.
|
|
+ */
|
|
+ sarea_priv->dirty |= (MACH64_UPLOAD_CONTEXT |
|
|
+ MACH64_UPLOAD_MISC | MACH64_UPLOAD_CLIPRECTS);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int mach64_get_param(struct drm_device *dev, void *data,
|
|
+ struct drm_file *file_priv)
|
|
+{
|
|
+ drm_mach64_private_t *dev_priv = dev->dev_private;
|
|
+ drm_mach64_getparam_t *param = data;
|
|
+ int value;
|
|
+
|
|
+ DRM_DEBUG("\n");
|
|
+
|
|
+ if (!dev_priv) {
|
|
+ DRM_ERROR("called with no initialization\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ switch (param->param) {
|
|
+ case MACH64_PARAM_FRAMES_QUEUED:
|
|
+ /* Needs lock since it calls mach64_ring_tick() */
|
|
+ LOCK_TEST_WITH_RETURN(dev, file_priv);
|
|
+ value = mach64_do_get_frames_queued(dev_priv);
|
|
+ break;
|
|
+ case MACH64_PARAM_IRQ_NR:
|
|
+ value = dev->irq;
|
|
+ break;
|
|
+ default:
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
|
|
+ DRM_ERROR("copy_to_user\n");
|
|
+ return -EFAULT;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
--- linux/drivers/gpu/drm/Kconfig.gpu-drm-mach64.orig
|
|
+++ linux/drivers/gpu/drm/Kconfig
|
|
@@ -267,6 +267,17 @@ config DRM_I810
|
|
selected, the module will be called i810. AGP support is required
|
|
for this driver to work.
|
|
|
|
+config DRM_MACH64
|
|
+ tristate "ATI Rage Pro (Mach64)"
|
|
+ depends on DRM && PCI
|
|
+ help
|
|
+ Choose this option if you have an ATI Rage Pro (mach64 chipset)
|
|
+ graphics card. Example cards include: 3D Rage Pro, Xpert 98,
|
|
+ 3D Rage LT Pro, 3D Rage XL/XC, and 3D Rage Mobility (P/M, M1).
|
|
+ Cards earlier than ATI Rage Pro (e.g. Rage II) are not supported.
|
|
+ If M is selected, the module will be called mach64. AGP support for
|
|
+ this card is strongly suggested (unless you have a PCI version).
|
|
+
|
|
config DRM_MGA
|
|
tristate "Matrox g200/g400"
|
|
depends on DRM && PCI
|
|
--- linux/drivers/gpu/drm/Makefile.gpu-drm-mach64.orig
|
|
+++ linux/drivers/gpu/drm/Makefile
|
|
@@ -47,6 +47,7 @@ obj-$(CONFIG_DRM_R128) += r128/
|
|
obj-$(CONFIG_HSA_AMD) += amd/amdkfd/
|
|
obj-$(CONFIG_DRM_RADEON)+= radeon/
|
|
obj-$(CONFIG_DRM_AMDGPU)+= amd/amdgpu/
|
|
+obj-$(CONFIG_DRM_MACH64)+= mach64/
|
|
obj-$(CONFIG_DRM_MGA) += mga/
|
|
obj-$(CONFIG_DRM_I810) += i810/
|
|
obj-$(CONFIG_DRM_I915) += i915/
|