mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 01:08:03 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
10
drivers/gpu/drm/r128/Makefile
Normal file
10
drivers/gpu/drm/r128/Makefile
Normal file
|
@ -0,0 +1,10 @@
|
|||
#
|
||||
# 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
|
||||
r128-y := r128_drv.o r128_cce.o r128_state.o r128_irq.o
|
||||
|
||||
r128-$(CONFIG_COMPAT) += r128_ioc32.o
|
||||
|
||||
obj-$(CONFIG_DRM_R128) += r128.o
|
937
drivers/gpu/drm/r128/r128_cce.c
Normal file
937
drivers/gpu/drm/r128/r128_cce.c
Normal file
|
@ -0,0 +1,937 @@
|
|||
/* r128_cce.c -- ATI Rage 128 driver -*- linux-c -*-
|
||||
* Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com
|
||||
*/
|
||||
/*
|
||||
* Copyright 2000 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Gareth Hughes <gareth@valinux.com>
|
||||
*/
|
||||
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/r128_drm.h>
|
||||
#include "r128_drv.h"
|
||||
|
||||
#define R128_FIFO_DEBUG 0
|
||||
|
||||
#define FIRMWARE_NAME "r128/r128_cce.bin"
|
||||
|
||||
MODULE_FIRMWARE(FIRMWARE_NAME);
|
||||
|
||||
static int R128_READ_PLL(struct drm_device *dev, int addr)
|
||||
{
|
||||
drm_r128_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f);
|
||||
return R128_READ(R128_CLOCK_CNTL_DATA);
|
||||
}
|
||||
|
||||
#if R128_FIFO_DEBUG
|
||||
static void r128_status(drm_r128_private_t *dev_priv)
|
||||
{
|
||||
printk("GUI_STAT = 0x%08x\n",
|
||||
(unsigned int)R128_READ(R128_GUI_STAT));
|
||||
printk("PM4_STAT = 0x%08x\n",
|
||||
(unsigned int)R128_READ(R128_PM4_STAT));
|
||||
printk("PM4_BUFFER_DL_WPTR = 0x%08x\n",
|
||||
(unsigned int)R128_READ(R128_PM4_BUFFER_DL_WPTR));
|
||||
printk("PM4_BUFFER_DL_RPTR = 0x%08x\n",
|
||||
(unsigned int)R128_READ(R128_PM4_BUFFER_DL_RPTR));
|
||||
printk("PM4_MICRO_CNTL = 0x%08x\n",
|
||||
(unsigned int)R128_READ(R128_PM4_MICRO_CNTL));
|
||||
printk("PM4_BUFFER_CNTL = 0x%08x\n",
|
||||
(unsigned int)R128_READ(R128_PM4_BUFFER_CNTL));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ================================================================
|
||||
* Engine, FIFO control
|
||||
*/
|
||||
|
||||
static int r128_do_pixcache_flush(drm_r128_private_t *dev_priv)
|
||||
{
|
||||
u32 tmp;
|
||||
int i;
|
||||
|
||||
tmp = R128_READ(R128_PC_NGUI_CTLSTAT) | R128_PC_FLUSH_ALL;
|
||||
R128_WRITE(R128_PC_NGUI_CTLSTAT, tmp);
|
||||
|
||||
for (i = 0; i < dev_priv->usec_timeout; i++) {
|
||||
if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY))
|
||||
return 0;
|
||||
DRM_UDELAY(1);
|
||||
}
|
||||
|
||||
#if R128_FIFO_DEBUG
|
||||
DRM_ERROR("failed!\n");
|
||||
#endif
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int r128_do_wait_for_fifo(drm_r128_private_t *dev_priv, int entries)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dev_priv->usec_timeout; i++) {
|
||||
int slots = R128_READ(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK;
|
||||
if (slots >= entries)
|
||||
return 0;
|
||||
DRM_UDELAY(1);
|
||||
}
|
||||
|
||||
#if R128_FIFO_DEBUG
|
||||
DRM_ERROR("failed!\n");
|
||||
#endif
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int r128_do_wait_for_idle(drm_r128_private_t *dev_priv)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
ret = r128_do_wait_for_fifo(dev_priv, 64);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < dev_priv->usec_timeout; i++) {
|
||||
if (!(R128_READ(R128_GUI_STAT) & R128_GUI_ACTIVE)) {
|
||||
r128_do_pixcache_flush(dev_priv);
|
||||
return 0;
|
||||
}
|
||||
DRM_UDELAY(1);
|
||||
}
|
||||
|
||||
#if R128_FIFO_DEBUG
|
||||
DRM_ERROR("failed!\n");
|
||||
#endif
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* CCE control, initialization
|
||||
*/
|
||||
|
||||
/* Load the microcode for the CCE */
|
||||
static int r128_cce_load_microcode(drm_r128_private_t *dev_priv)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
const struct firmware *fw;
|
||||
const __be32 *fw_data;
|
||||
int rc, i;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
pdev = platform_device_register_simple("r128_cce", 0, NULL, 0);
|
||||
if (IS_ERR(pdev)) {
|
||||
printk(KERN_ERR "r128_cce: Failed to register firmware\n");
|
||||
return PTR_ERR(pdev);
|
||||
}
|
||||
rc = request_firmware(&fw, FIRMWARE_NAME, &pdev->dev);
|
||||
platform_device_unregister(pdev);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "r128_cce: Failed to load firmware \"%s\"\n",
|
||||
FIRMWARE_NAME);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (fw->size != 256 * 8) {
|
||||
printk(KERN_ERR
|
||||
"r128_cce: Bogus length %zu in firmware \"%s\"\n",
|
||||
fw->size, FIRMWARE_NAME);
|
||||
rc = -EINVAL;
|
||||
goto out_release;
|
||||
}
|
||||
|
||||
r128_do_wait_for_idle(dev_priv);
|
||||
|
||||
fw_data = (const __be32 *)fw->data;
|
||||
R128_WRITE(R128_PM4_MICROCODE_ADDR, 0);
|
||||
for (i = 0; i < 256; i++) {
|
||||
R128_WRITE(R128_PM4_MICROCODE_DATAH,
|
||||
be32_to_cpup(&fw_data[i * 2]));
|
||||
R128_WRITE(R128_PM4_MICROCODE_DATAL,
|
||||
be32_to_cpup(&fw_data[i * 2 + 1]));
|
||||
}
|
||||
|
||||
out_release:
|
||||
release_firmware(fw);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Flush any pending commands to the CCE. This should only be used just
|
||||
* prior to a wait for idle, as it informs the engine that the command
|
||||
* stream is ending.
|
||||
*/
|
||||
static void r128_do_cce_flush(drm_r128_private_t *dev_priv)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
tmp = R128_READ(R128_PM4_BUFFER_DL_WPTR) | R128_PM4_BUFFER_DL_DONE;
|
||||
R128_WRITE(R128_PM4_BUFFER_DL_WPTR, tmp);
|
||||
}
|
||||
|
||||
/* Wait for the CCE to go idle.
|
||||
*/
|
||||
int r128_do_cce_idle(drm_r128_private_t *dev_priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dev_priv->usec_timeout; i++) {
|
||||
if (GET_RING_HEAD(dev_priv) == dev_priv->ring.tail) {
|
||||
int pm4stat = R128_READ(R128_PM4_STAT);
|
||||
if (((pm4stat & R128_PM4_FIFOCNT_MASK) >=
|
||||
dev_priv->cce_fifo_size) &&
|
||||
!(pm4stat & (R128_PM4_BUSY |
|
||||
R128_PM4_GUI_ACTIVE))) {
|
||||
return r128_do_pixcache_flush(dev_priv);
|
||||
}
|
||||
}
|
||||
DRM_UDELAY(1);
|
||||
}
|
||||
|
||||
#if R128_FIFO_DEBUG
|
||||
DRM_ERROR("failed!\n");
|
||||
r128_status(dev_priv);
|
||||
#endif
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Start the Concurrent Command Engine.
|
||||
*/
|
||||
static void r128_do_cce_start(drm_r128_private_t *dev_priv)
|
||||
{
|
||||
r128_do_wait_for_idle(dev_priv);
|
||||
|
||||
R128_WRITE(R128_PM4_BUFFER_CNTL,
|
||||
dev_priv->cce_mode | dev_priv->ring.size_l2qw
|
||||
| R128_PM4_BUFFER_CNTL_NOUPDATE);
|
||||
R128_READ(R128_PM4_BUFFER_ADDR); /* as per the sample code */
|
||||
R128_WRITE(R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN);
|
||||
|
||||
dev_priv->cce_running = 1;
|
||||
}
|
||||
|
||||
/* Reset the Concurrent Command Engine. This will not flush any pending
|
||||
* commands, so you must wait for the CCE command stream to complete
|
||||
* before calling this routine.
|
||||
*/
|
||||
static void r128_do_cce_reset(drm_r128_private_t *dev_priv)
|
||||
{
|
||||
R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0);
|
||||
R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0);
|
||||
dev_priv->ring.tail = 0;
|
||||
}
|
||||
|
||||
/* Stop the Concurrent Command Engine. This will not flush any pending
|
||||
* commands, so you must flush the command stream and wait for the CCE
|
||||
* to go idle before calling this routine.
|
||||
*/
|
||||
static void r128_do_cce_stop(drm_r128_private_t *dev_priv)
|
||||
{
|
||||
R128_WRITE(R128_PM4_MICRO_CNTL, 0);
|
||||
R128_WRITE(R128_PM4_BUFFER_CNTL,
|
||||
R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE);
|
||||
|
||||
dev_priv->cce_running = 0;
|
||||
}
|
||||
|
||||
/* Reset the engine. This will stop the CCE if it is running.
|
||||
*/
|
||||
static int r128_do_engine_reset(struct drm_device *dev)
|
||||
{
|
||||
drm_r128_private_t *dev_priv = dev->dev_private;
|
||||
u32 clock_cntl_index, mclk_cntl, gen_reset_cntl;
|
||||
|
||||
r128_do_pixcache_flush(dev_priv);
|
||||
|
||||
clock_cntl_index = R128_READ(R128_CLOCK_CNTL_INDEX);
|
||||
mclk_cntl = R128_READ_PLL(dev, R128_MCLK_CNTL);
|
||||
|
||||
R128_WRITE_PLL(R128_MCLK_CNTL,
|
||||
mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP);
|
||||
|
||||
gen_reset_cntl = R128_READ(R128_GEN_RESET_CNTL);
|
||||
|
||||
/* Taken from the sample code - do not change */
|
||||
R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl | R128_SOFT_RESET_GUI);
|
||||
R128_READ(R128_GEN_RESET_CNTL);
|
||||
R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl & ~R128_SOFT_RESET_GUI);
|
||||
R128_READ(R128_GEN_RESET_CNTL);
|
||||
|
||||
R128_WRITE_PLL(R128_MCLK_CNTL, mclk_cntl);
|
||||
R128_WRITE(R128_CLOCK_CNTL_INDEX, clock_cntl_index);
|
||||
R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl);
|
||||
|
||||
/* Reset the CCE ring */
|
||||
r128_do_cce_reset(dev_priv);
|
||||
|
||||
/* The CCE is no longer running after an engine reset */
|
||||
dev_priv->cce_running = 0;
|
||||
|
||||
/* Reset any pending vertex, indirect buffers */
|
||||
r128_freelist_reset(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void r128_cce_init_ring_buffer(struct drm_device *dev,
|
||||
drm_r128_private_t *dev_priv)
|
||||
{
|
||||
u32 ring_start;
|
||||
u32 tmp;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
/* The manual (p. 2) says this address is in "VM space". This
|
||||
* means it's an offset from the start of AGP space.
|
||||
*/
|
||||
#if __OS_HAS_AGP
|
||||
if (!dev_priv->is_pci)
|
||||
ring_start = dev_priv->cce_ring->offset - dev->agp->base;
|
||||
else
|
||||
#endif
|
||||
ring_start = dev_priv->cce_ring->offset -
|
||||
(unsigned long)dev->sg->virtual;
|
||||
|
||||
R128_WRITE(R128_PM4_BUFFER_OFFSET, ring_start | R128_AGP_OFFSET);
|
||||
|
||||
R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0);
|
||||
R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0);
|
||||
|
||||
/* Set watermark control */
|
||||
R128_WRITE(R128_PM4_BUFFER_WM_CNTL,
|
||||
((R128_WATERMARK_L / 4) << R128_WMA_SHIFT)
|
||||
| ((R128_WATERMARK_M / 4) << R128_WMB_SHIFT)
|
||||
| ((R128_WATERMARK_N / 4) << R128_WMC_SHIFT)
|
||||
| ((R128_WATERMARK_K / 64) << R128_WB_WM_SHIFT));
|
||||
|
||||
/* Force read. Why? Because it's in the examples... */
|
||||
R128_READ(R128_PM4_BUFFER_ADDR);
|
||||
|
||||
/* Turn on bus mastering */
|
||||
tmp = R128_READ(R128_BUS_CNTL) & ~R128_BUS_MASTER_DIS;
|
||||
R128_WRITE(R128_BUS_CNTL, tmp);
|
||||
}
|
||||
|
||||
static int r128_do_init_cce(struct drm_device *dev, drm_r128_init_t *init)
|
||||
{
|
||||
drm_r128_private_t *dev_priv;
|
||||
int rc;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
if (dev->dev_private) {
|
||||
DRM_DEBUG("called when already initialized\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_priv = kzalloc(sizeof(drm_r128_private_t), GFP_KERNEL);
|
||||
if (dev_priv == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_priv->is_pci = init->is_pci;
|
||||
|
||||
if (dev_priv->is_pci && !dev->sg) {
|
||||
DRM_ERROR("PCI GART memory not allocated!\n");
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
r128_do_cleanup_cce(dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_priv->usec_timeout = init->usec_timeout;
|
||||
if (dev_priv->usec_timeout < 1 ||
|
||||
dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT) {
|
||||
DRM_DEBUG("TIMEOUT problem!\n");
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
r128_do_cleanup_cce(dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_priv->cce_mode = init->cce_mode;
|
||||
|
||||
/* GH: Simple idle check.
|
||||
*/
|
||||
atomic_set(&dev_priv->idle_count, 0);
|
||||
|
||||
/* We don't support anything other than bus-mastering ring mode,
|
||||
* but the ring can be in either AGP or PCI space for the ring
|
||||
* read pointer.
|
||||
*/
|
||||
if ((init->cce_mode != R128_PM4_192BM) &&
|
||||
(init->cce_mode != R128_PM4_128BM_64INDBM) &&
|
||||
(init->cce_mode != R128_PM4_64BM_128INDBM) &&
|
||||
(init->cce_mode != R128_PM4_64BM_64VCBM_64INDBM)) {
|
||||
DRM_DEBUG("Bad cce_mode!\n");
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
r128_do_cleanup_cce(dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (init->cce_mode) {
|
||||
case R128_PM4_NONPM4:
|
||||
dev_priv->cce_fifo_size = 0;
|
||||
break;
|
||||
case R128_PM4_192PIO:
|
||||
case R128_PM4_192BM:
|
||||
dev_priv->cce_fifo_size = 192;
|
||||
break;
|
||||
case R128_PM4_128PIO_64INDBM:
|
||||
case R128_PM4_128BM_64INDBM:
|
||||
dev_priv->cce_fifo_size = 128;
|
||||
break;
|
||||
case R128_PM4_64PIO_128INDBM:
|
||||
case R128_PM4_64BM_128INDBM:
|
||||
case R128_PM4_64PIO_64VCBM_64INDBM:
|
||||
case R128_PM4_64BM_64VCBM_64INDBM:
|
||||
case R128_PM4_64PIO_64VCPIO_64INDPIO:
|
||||
dev_priv->cce_fifo_size = 64;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (init->fb_bpp) {
|
||||
case 16:
|
||||
dev_priv->color_fmt = R128_DATATYPE_RGB565;
|
||||
break;
|
||||
case 32:
|
||||
default:
|
||||
dev_priv->color_fmt = R128_DATATYPE_ARGB8888;
|
||||
break;
|
||||
}
|
||||
dev_priv->front_offset = init->front_offset;
|
||||
dev_priv->front_pitch = init->front_pitch;
|
||||
dev_priv->back_offset = init->back_offset;
|
||||
dev_priv->back_pitch = init->back_pitch;
|
||||
|
||||
switch (init->depth_bpp) {
|
||||
case 16:
|
||||
dev_priv->depth_fmt = R128_DATATYPE_RGB565;
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
default:
|
||||
dev_priv->depth_fmt = R128_DATATYPE_ARGB8888;
|
||||
break;
|
||||
}
|
||||
dev_priv->depth_offset = init->depth_offset;
|
||||
dev_priv->depth_pitch = init->depth_pitch;
|
||||
dev_priv->span_offset = init->span_offset;
|
||||
|
||||
dev_priv->front_pitch_offset_c = (((dev_priv->front_pitch / 8) << 21) |
|
||||
(dev_priv->front_offset >> 5));
|
||||
dev_priv->back_pitch_offset_c = (((dev_priv->back_pitch / 8) << 21) |
|
||||
(dev_priv->back_offset >> 5));
|
||||
dev_priv->depth_pitch_offset_c = (((dev_priv->depth_pitch / 8) << 21) |
|
||||
(dev_priv->depth_offset >> 5) |
|
||||
R128_DST_TILE);
|
||||
dev_priv->span_pitch_offset_c = (((dev_priv->depth_pitch / 8) << 21) |
|
||||
(dev_priv->span_offset >> 5));
|
||||
|
||||
dev_priv->sarea = drm_legacy_getsarea(dev);
|
||||
if (!dev_priv->sarea) {
|
||||
DRM_ERROR("could not find sarea!\n");
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
r128_do_cleanup_cce(dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_priv->mmio = drm_legacy_findmap(dev, init->mmio_offset);
|
||||
if (!dev_priv->mmio) {
|
||||
DRM_ERROR("could not find mmio region!\n");
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
r128_do_cleanup_cce(dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
dev_priv->cce_ring = drm_legacy_findmap(dev, init->ring_offset);
|
||||
if (!dev_priv->cce_ring) {
|
||||
DRM_ERROR("could not find cce ring region!\n");
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
r128_do_cleanup_cce(dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
dev_priv->ring_rptr = drm_legacy_findmap(dev, init->ring_rptr_offset);
|
||||
if (!dev_priv->ring_rptr) {
|
||||
DRM_ERROR("could not find ring read pointer!\n");
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
r128_do_cleanup_cce(dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
dev->agp_buffer_token = init->buffers_offset;
|
||||
dev->agp_buffer_map = drm_legacy_findmap(dev, init->buffers_offset);
|
||||
if (!dev->agp_buffer_map) {
|
||||
DRM_ERROR("could not find dma buffer region!\n");
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
r128_do_cleanup_cce(dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!dev_priv->is_pci) {
|
||||
dev_priv->agp_textures =
|
||||
drm_legacy_findmap(dev, init->agp_textures_offset);
|
||||
if (!dev_priv->agp_textures) {
|
||||
DRM_ERROR("could not find agp texture region!\n");
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
r128_do_cleanup_cce(dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
dev_priv->sarea_priv =
|
||||
(drm_r128_sarea_t *) ((u8 *) dev_priv->sarea->handle +
|
||||
init->sarea_priv_offset);
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
if (!dev_priv->is_pci) {
|
||||
drm_legacy_ioremap_wc(dev_priv->cce_ring, dev);
|
||||
drm_legacy_ioremap_wc(dev_priv->ring_rptr, dev);
|
||||
drm_legacy_ioremap_wc(dev->agp_buffer_map, dev);
|
||||
if (!dev_priv->cce_ring->handle ||
|
||||
!dev_priv->ring_rptr->handle ||
|
||||
!dev->agp_buffer_map->handle) {
|
||||
DRM_ERROR("Could not ioremap agp regions!\n");
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
r128_do_cleanup_cce(dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
dev_priv->cce_ring->handle =
|
||||
(void *)(unsigned long)dev_priv->cce_ring->offset;
|
||||
dev_priv->ring_rptr->handle =
|
||||
(void *)(unsigned long)dev_priv->ring_rptr->offset;
|
||||
dev->agp_buffer_map->handle =
|
||||
(void *)(unsigned long)dev->agp_buffer_map->offset;
|
||||
}
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
if (!dev_priv->is_pci)
|
||||
dev_priv->cce_buffers_offset = dev->agp->base;
|
||||
else
|
||||
#endif
|
||||
dev_priv->cce_buffers_offset = (unsigned long)dev->sg->virtual;
|
||||
|
||||
dev_priv->ring.start = (u32 *) dev_priv->cce_ring->handle;
|
||||
dev_priv->ring.end = ((u32 *) dev_priv->cce_ring->handle
|
||||
+ init->ring_size / sizeof(u32));
|
||||
dev_priv->ring.size = init->ring_size;
|
||||
dev_priv->ring.size_l2qw = order_base_2(init->ring_size / 8);
|
||||
|
||||
dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1;
|
||||
|
||||
dev_priv->ring.high_mark = 128;
|
||||
|
||||
dev_priv->sarea_priv->last_frame = 0;
|
||||
R128_WRITE(R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame);
|
||||
|
||||
dev_priv->sarea_priv->last_dispatch = 0;
|
||||
R128_WRITE(R128_LAST_DISPATCH_REG, dev_priv->sarea_priv->last_dispatch);
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
if (dev_priv->is_pci) {
|
||||
#endif
|
||||
dev_priv->gart_info.table_mask = DMA_BIT_MASK(32);
|
||||
dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN;
|
||||
dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE;
|
||||
dev_priv->gart_info.addr = NULL;
|
||||
dev_priv->gart_info.bus_addr = 0;
|
||||
dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
|
||||
if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
|
||||
DRM_ERROR("failed to init PCI GART!\n");
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
r128_do_cleanup_cce(dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
R128_WRITE(R128_PCI_GART_PAGE, dev_priv->gart_info.bus_addr);
|
||||
#if __OS_HAS_AGP
|
||||
}
|
||||
#endif
|
||||
|
||||
r128_cce_init_ring_buffer(dev, dev_priv);
|
||||
rc = r128_cce_load_microcode(dev_priv);
|
||||
|
||||
dev->dev_private = (void *)dev_priv;
|
||||
|
||||
r128_do_engine_reset(dev);
|
||||
|
||||
if (rc) {
|
||||
DRM_ERROR("Failed to load firmware!\n");
|
||||
r128_do_cleanup_cce(dev);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int r128_do_cleanup_cce(struct drm_device *dev)
|
||||
{
|
||||
|
||||
/* Make sure interrupts are disabled here because the uninstall ioctl
|
||||
* may not have been called from userspace and after dev_private
|
||||
* is freed, it's too late.
|
||||
*/
|
||||
if (dev->irq_enabled)
|
||||
drm_irq_uninstall(dev);
|
||||
|
||||
if (dev->dev_private) {
|
||||
drm_r128_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
#if __OS_HAS_AGP
|
||||
if (!dev_priv->is_pci) {
|
||||
if (dev_priv->cce_ring != NULL)
|
||||
drm_legacy_ioremapfree(dev_priv->cce_ring, dev);
|
||||
if (dev_priv->ring_rptr != NULL)
|
||||
drm_legacy_ioremapfree(dev_priv->ring_rptr, dev);
|
||||
if (dev->agp_buffer_map != NULL) {
|
||||
drm_legacy_ioremapfree(dev->agp_buffer_map, dev);
|
||||
dev->agp_buffer_map = NULL;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (dev_priv->gart_info.bus_addr)
|
||||
if (!drm_ati_pcigart_cleanup(dev,
|
||||
&dev_priv->gart_info))
|
||||
DRM_ERROR
|
||||
("failed to cleanup PCI GART!\n");
|
||||
}
|
||||
|
||||
kfree(dev->dev_private);
|
||||
dev->dev_private = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
drm_r128_init_t *init = data;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||
|
||||
switch (init->func) {
|
||||
case R128_INIT_CCE:
|
||||
return r128_do_init_cce(dev, init);
|
||||
case R128_CLEANUP_CCE:
|
||||
return r128_do_cleanup_cce(dev);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
drm_r128_private_t *dev_priv = dev->dev_private;
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||
|
||||
DEV_INIT_TEST_WITH_RETURN(dev_priv);
|
||||
|
||||
if (dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4) {
|
||||
DRM_DEBUG("while CCE running\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r128_do_cce_start(dev_priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Stop the CCE. The engine must have been idled before calling this
|
||||
* routine.
|
||||
*/
|
||||
int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
drm_r128_private_t *dev_priv = dev->dev_private;
|
||||
drm_r128_cce_stop_t *stop = data;
|
||||
int ret;
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||
|
||||
DEV_INIT_TEST_WITH_RETURN(dev_priv);
|
||||
|
||||
/* Flush any pending CCE commands. This ensures any outstanding
|
||||
* commands are exectuted by the engine before we turn it off.
|
||||
*/
|
||||
if (stop->flush)
|
||||
r128_do_cce_flush(dev_priv);
|
||||
|
||||
/* If we fail to make the engine go idle, we return an error
|
||||
* code so that the DRM ioctl wrapper can try again.
|
||||
*/
|
||||
if (stop->idle) {
|
||||
ret = r128_do_cce_idle(dev_priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Finally, we can turn off the CCE. If the engine isn't idle,
|
||||
* we will get some dropped triangles as they won't be fully
|
||||
* rendered before the CCE is shut down.
|
||||
*/
|
||||
r128_do_cce_stop(dev_priv);
|
||||
|
||||
/* Reset the engine */
|
||||
r128_do_engine_reset(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Just reset the CCE ring. Called as part of an X Server engine reset.
|
||||
*/
|
||||
int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
drm_r128_private_t *dev_priv = dev->dev_private;
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||
|
||||
DEV_INIT_TEST_WITH_RETURN(dev_priv);
|
||||
|
||||
r128_do_cce_reset(dev_priv);
|
||||
|
||||
/* The CCE is no longer running after an engine reset */
|
||||
dev_priv->cce_running = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
drm_r128_private_t *dev_priv = dev->dev_private;
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||
|
||||
DEV_INIT_TEST_WITH_RETURN(dev_priv);
|
||||
|
||||
if (dev_priv->cce_running)
|
||||
r128_do_cce_flush(dev_priv);
|
||||
|
||||
return r128_do_cce_idle(dev_priv);
|
||||
}
|
||||
|
||||
int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||
|
||||
DEV_INIT_TEST_WITH_RETURN(dev->dev_private);
|
||||
|
||||
return r128_do_engine_reset(dev);
|
||||
}
|
||||
|
||||
int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* Freelist management
|
||||
*/
|
||||
#define R128_BUFFER_USED 0xffffffff
|
||||
#define R128_BUFFER_FREE 0
|
||||
|
||||
#if 0
|
||||
static int r128_freelist_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_device_dma *dma = dev->dma;
|
||||
drm_r128_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_buf *buf;
|
||||
drm_r128_buf_priv_t *buf_priv;
|
||||
drm_r128_freelist_t *entry;
|
||||
int i;
|
||||
|
||||
dev_priv->head = kzalloc(sizeof(drm_r128_freelist_t), GFP_KERNEL);
|
||||
if (dev_priv->head == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_priv->head->age = R128_BUFFER_USED;
|
||||
|
||||
for (i = 0; i < dma->buf_count; i++) {
|
||||
buf = dma->buflist[i];
|
||||
buf_priv = buf->dev_private;
|
||||
|
||||
entry = kmalloc(sizeof(drm_r128_freelist_t), GFP_KERNEL);
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
|
||||
entry->age = R128_BUFFER_FREE;
|
||||
entry->buf = buf;
|
||||
entry->prev = dev_priv->head;
|
||||
entry->next = dev_priv->head->next;
|
||||
if (!entry->next)
|
||||
dev_priv->tail = entry;
|
||||
|
||||
buf_priv->discard = 0;
|
||||
buf_priv->dispatched = 0;
|
||||
buf_priv->list_entry = entry;
|
||||
|
||||
dev_priv->head->next = entry;
|
||||
|
||||
if (dev_priv->head->next)
|
||||
dev_priv->head->next->prev = entry;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct drm_buf *r128_freelist_get(struct drm_device * dev)
|
||||
{
|
||||
struct drm_device_dma *dma = dev->dma;
|
||||
drm_r128_private_t *dev_priv = dev->dev_private;
|
||||
drm_r128_buf_priv_t *buf_priv;
|
||||
struct drm_buf *buf;
|
||||
int i, t;
|
||||
|
||||
/* FIXME: Optimize -- use freelist code */
|
||||
|
||||
for (i = 0; i < dma->buf_count; i++) {
|
||||
buf = dma->buflist[i];
|
||||
buf_priv = buf->dev_private;
|
||||
if (!buf->file_priv)
|
||||
return buf;
|
||||
}
|
||||
|
||||
for (t = 0; t < dev_priv->usec_timeout; t++) {
|
||||
u32 done_age = R128_READ(R128_LAST_DISPATCH_REG);
|
||||
|
||||
for (i = 0; i < dma->buf_count; i++) {
|
||||
buf = dma->buflist[i];
|
||||
buf_priv = buf->dev_private;
|
||||
if (buf->pending && buf_priv->age <= done_age) {
|
||||
/* The buffer has been processed, so it
|
||||
* can now be used.
|
||||
*/
|
||||
buf->pending = 0;
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
DRM_UDELAY(1);
|
||||
}
|
||||
|
||||
DRM_DEBUG("returning NULL!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void r128_freelist_reset(struct drm_device *dev)
|
||||
{
|
||||
struct drm_device_dma *dma = dev->dma;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dma->buf_count; i++) {
|
||||
struct drm_buf *buf = dma->buflist[i];
|
||||
drm_r128_buf_priv_t *buf_priv = buf->dev_private;
|
||||
buf_priv->age = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* CCE command submission
|
||||
*/
|
||||
|
||||
int r128_wait_ring(drm_r128_private_t *dev_priv, int n)
|
||||
{
|
||||
drm_r128_ring_buffer_t *ring = &dev_priv->ring;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dev_priv->usec_timeout; i++) {
|
||||
r128_update_ring_snapshot(dev_priv);
|
||||
if (ring->space >= n)
|
||||
return 0;
|
||||
DRM_UDELAY(1);
|
||||
}
|
||||
|
||||
/* FIXME: This is being ignored... */
|
||||
DRM_ERROR("failed!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int r128_cce_get_buffers(struct drm_device *dev,
|
||||
struct drm_file *file_priv,
|
||||
struct drm_dma *d)
|
||||
{
|
||||
int i;
|
||||
struct drm_buf *buf;
|
||||
|
||||
for (i = d->granted_count; i < d->request_count; i++) {
|
||||
buf = r128_freelist_get(dev);
|
||||
if (!buf)
|
||||
return -EAGAIN;
|
||||
|
||||
buf->file_priv = file_priv;
|
||||
|
||||
if (copy_to_user(&d->request_indices[i], &buf->idx,
|
||||
sizeof(buf->idx)))
|
||||
return -EFAULT;
|
||||
if (copy_to_user(&d->request_sizes[i], &buf->total,
|
||||
sizeof(buf->total)))
|
||||
return -EFAULT;
|
||||
|
||||
d->granted_count++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_device_dma *dma = dev->dma;
|
||||
int ret = 0;
|
||||
struct drm_dma *d = data;
|
||||
|
||||
LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||
|
||||
/* Please don't send us buffers.
|
||||
*/
|
||||
if (d->send_count != 0) {
|
||||
DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
|
||||
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);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
d->granted_count = 0;
|
||||
|
||||
if (d->request_count)
|
||||
ret = r128_cce_get_buffers(dev, file_priv, d);
|
||||
|
||||
return ret;
|
||||
}
|
112
drivers/gpu/drm/r128/r128_drv.c
Normal file
112
drivers/gpu/drm/r128/r128_drv.c
Normal file
|
@ -0,0 +1,112 @@
|
|||
/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*-
|
||||
* Created: Mon Dec 13 09:47:27 1999 by faith@precisioninsight.com
|
||||
*
|
||||
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* Gareth Hughes <gareth@valinux.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/r128_drm.h>
|
||||
#include "r128_drv.h"
|
||||
|
||||
#include <drm/drm_pciids.h>
|
||||
|
||||
static struct pci_device_id pciidlist[] = {
|
||||
r128_PCI_IDS
|
||||
};
|
||||
|
||||
static const struct file_operations r128_driver_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.release = drm_release,
|
||||
.unlocked_ioctl = drm_ioctl,
|
||||
.mmap = drm_legacy_mmap,
|
||||
.poll = drm_poll,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = r128_compat_ioctl,
|
||||
#endif
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
static struct drm_driver driver = {
|
||||
.driver_features =
|
||||
DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG |
|
||||
DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
|
||||
.dev_priv_size = sizeof(drm_r128_buf_priv_t),
|
||||
.load = r128_driver_load,
|
||||
.preclose = r128_driver_preclose,
|
||||
.lastclose = r128_driver_lastclose,
|
||||
.set_busid = drm_pci_set_busid,
|
||||
.get_vblank_counter = r128_get_vblank_counter,
|
||||
.enable_vblank = r128_enable_vblank,
|
||||
.disable_vblank = r128_disable_vblank,
|
||||
.irq_preinstall = r128_driver_irq_preinstall,
|
||||
.irq_postinstall = r128_driver_irq_postinstall,
|
||||
.irq_uninstall = r128_driver_irq_uninstall,
|
||||
.irq_handler = r128_driver_irq_handler,
|
||||
.ioctls = r128_ioctls,
|
||||
.dma_ioctl = r128_cce_buffers,
|
||||
.fops = &r128_driver_fops,
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
.date = DRIVER_DATE,
|
||||
.major = DRIVER_MAJOR,
|
||||
.minor = DRIVER_MINOR,
|
||||
.patchlevel = DRIVER_PATCHLEVEL,
|
||||
};
|
||||
|
||||
int r128_driver_load(struct drm_device *dev, unsigned long flags)
|
||||
{
|
||||
pci_set_master(dev->pdev);
|
||||
return drm_vblank_init(dev, 1);
|
||||
}
|
||||
|
||||
static struct pci_driver r128_pci_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.id_table = pciidlist,
|
||||
};
|
||||
|
||||
static int __init r128_init(void)
|
||||
{
|
||||
driver.num_ioctls = r128_max_ioctl;
|
||||
|
||||
return drm_pci_init(&driver, &r128_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit r128_exit(void)
|
||||
{
|
||||
drm_pci_exit(&driver, &r128_pci_driver);
|
||||
}
|
||||
|
||||
module_init(r128_init);
|
||||
module_exit(r128_exit);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL and additional rights");
|
533
drivers/gpu/drm/r128/r128_drv.h
Normal file
533
drivers/gpu/drm/r128/r128_drv.h
Normal file
|
@ -0,0 +1,533 @@
|
|||
/* r128_drv.h -- Private header for r128 driver -*- linux-c -*-
|
||||
* Created: Mon Dec 13 09:51:11 1999 by faith@precisioninsight.com
|
||||
*/
|
||||
/*
|
||||
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
|
||||
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Rickard E. (Rik) Faith <faith@valinux.com>
|
||||
* Kevin E. Martin <martin@valinux.com>
|
||||
* Gareth Hughes <gareth@valinux.com>
|
||||
* Michel D<EFBFBD>zer <daenzerm@student.ethz.ch>
|
||||
*/
|
||||
|
||||
#ifndef __R128_DRV_H__
|
||||
#define __R128_DRV_H__
|
||||
|
||||
#include <drm/ati_pcigart.h>
|
||||
#include <drm/drm_legacy.h>
|
||||
|
||||
/* General customization:
|
||||
*/
|
||||
#define DRIVER_AUTHOR "Gareth Hughes, VA Linux Systems Inc."
|
||||
|
||||
#define DRIVER_NAME "r128"
|
||||
#define DRIVER_DESC "ATI Rage 128"
|
||||
#define DRIVER_DATE "20030725"
|
||||
|
||||
/* Interface history:
|
||||
*
|
||||
* ?? - ??
|
||||
* 2.4 - Add support for ycbcr textures (no new ioctls)
|
||||
* 2.5 - Add FLIP ioctl, disable FULLSCREEN.
|
||||
*/
|
||||
#define DRIVER_MAJOR 2
|
||||
#define DRIVER_MINOR 5
|
||||
#define DRIVER_PATCHLEVEL 0
|
||||
|
||||
#define GET_RING_HEAD(dev_priv) R128_READ(R128_PM4_BUFFER_DL_RPTR)
|
||||
|
||||
typedef struct drm_r128_freelist {
|
||||
unsigned int age;
|
||||
struct drm_buf *buf;
|
||||
struct drm_r128_freelist *next;
|
||||
struct drm_r128_freelist *prev;
|
||||
} drm_r128_freelist_t;
|
||||
|
||||
typedef struct drm_r128_ring_buffer {
|
||||
u32 *start;
|
||||
u32 *end;
|
||||
int size;
|
||||
int size_l2qw;
|
||||
|
||||
u32 tail;
|
||||
u32 tail_mask;
|
||||
int space;
|
||||
|
||||
int high_mark;
|
||||
} drm_r128_ring_buffer_t;
|
||||
|
||||
typedef struct drm_r128_private {
|
||||
drm_r128_ring_buffer_t ring;
|
||||
drm_r128_sarea_t *sarea_priv;
|
||||
|
||||
int cce_mode;
|
||||
int cce_fifo_size;
|
||||
int cce_running;
|
||||
|
||||
drm_r128_freelist_t *head;
|
||||
drm_r128_freelist_t *tail;
|
||||
|
||||
int usec_timeout;
|
||||
int is_pci;
|
||||
unsigned long cce_buffers_offset;
|
||||
|
||||
atomic_t idle_count;
|
||||
|
||||
int page_flipping;
|
||||
int current_page;
|
||||
u32 crtc_offset;
|
||||
u32 crtc_offset_cntl;
|
||||
|
||||
atomic_t vbl_received;
|
||||
|
||||
u32 color_fmt;
|
||||
unsigned int front_offset;
|
||||
unsigned int front_pitch;
|
||||
unsigned int back_offset;
|
||||
unsigned int back_pitch;
|
||||
|
||||
u32 depth_fmt;
|
||||
unsigned int depth_offset;
|
||||
unsigned int depth_pitch;
|
||||
unsigned int span_offset;
|
||||
|
||||
u32 front_pitch_offset_c;
|
||||
u32 back_pitch_offset_c;
|
||||
u32 depth_pitch_offset_c;
|
||||
u32 span_pitch_offset_c;
|
||||
|
||||
drm_local_map_t *sarea;
|
||||
drm_local_map_t *mmio;
|
||||
drm_local_map_t *cce_ring;
|
||||
drm_local_map_t *ring_rptr;
|
||||
drm_local_map_t *agp_textures;
|
||||
struct drm_ati_pcigart_info gart_info;
|
||||
} drm_r128_private_t;
|
||||
|
||||
typedef struct drm_r128_buf_priv {
|
||||
u32 age;
|
||||
int prim;
|
||||
int discard;
|
||||
int dispatched;
|
||||
drm_r128_freelist_t *list_entry;
|
||||
} drm_r128_buf_priv_t;
|
||||
|
||||
extern const struct drm_ioctl_desc r128_ioctls[];
|
||||
extern int r128_max_ioctl;
|
||||
|
||||
/* r128_cce.c */
|
||||
extern int r128_cce_init(struct drm_device *dev, void *data, struct drm_file *file_priv);
|
||||
extern int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_priv);
|
||||
extern int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv);
|
||||
extern int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
|
||||
extern int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv);
|
||||
extern int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv);
|
||||
extern int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv);
|
||||
extern int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv);
|
||||
|
||||
extern void r128_freelist_reset(struct drm_device *dev);
|
||||
|
||||
extern int r128_wait_ring(drm_r128_private_t *dev_priv, int n);
|
||||
|
||||
extern int r128_do_cce_idle(drm_r128_private_t *dev_priv);
|
||||
extern int r128_do_cleanup_cce(struct drm_device *dev);
|
||||
|
||||
extern int r128_enable_vblank(struct drm_device *dev, int crtc);
|
||||
extern void r128_disable_vblank(struct drm_device *dev, int crtc);
|
||||
extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc);
|
||||
extern irqreturn_t r128_driver_irq_handler(int irq, void *arg);
|
||||
extern void r128_driver_irq_preinstall(struct drm_device *dev);
|
||||
extern int r128_driver_irq_postinstall(struct drm_device *dev);
|
||||
extern void r128_driver_irq_uninstall(struct drm_device *dev);
|
||||
extern void r128_driver_lastclose(struct drm_device *dev);
|
||||
extern int r128_driver_load(struct drm_device *dev, unsigned long flags);
|
||||
extern void r128_driver_preclose(struct drm_device *dev,
|
||||
struct drm_file *file_priv);
|
||||
|
||||
extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg);
|
||||
|
||||
/* Register definitions, register access macros and drmAddMap constants
|
||||
* for Rage 128 kernel driver.
|
||||
*/
|
||||
|
||||
#define R128_AUX_SC_CNTL 0x1660
|
||||
# define R128_AUX1_SC_EN (1 << 0)
|
||||
# define R128_AUX1_SC_MODE_OR (0 << 1)
|
||||
# define R128_AUX1_SC_MODE_NAND (1 << 1)
|
||||
# define R128_AUX2_SC_EN (1 << 2)
|
||||
# define R128_AUX2_SC_MODE_OR (0 << 3)
|
||||
# define R128_AUX2_SC_MODE_NAND (1 << 3)
|
||||
# define R128_AUX3_SC_EN (1 << 4)
|
||||
# define R128_AUX3_SC_MODE_OR (0 << 5)
|
||||
# define R128_AUX3_SC_MODE_NAND (1 << 5)
|
||||
#define R128_AUX1_SC_LEFT 0x1664
|
||||
#define R128_AUX1_SC_RIGHT 0x1668
|
||||
#define R128_AUX1_SC_TOP 0x166c
|
||||
#define R128_AUX1_SC_BOTTOM 0x1670
|
||||
#define R128_AUX2_SC_LEFT 0x1674
|
||||
#define R128_AUX2_SC_RIGHT 0x1678
|
||||
#define R128_AUX2_SC_TOP 0x167c
|
||||
#define R128_AUX2_SC_BOTTOM 0x1680
|
||||
#define R128_AUX3_SC_LEFT 0x1684
|
||||
#define R128_AUX3_SC_RIGHT 0x1688
|
||||
#define R128_AUX3_SC_TOP 0x168c
|
||||
#define R128_AUX3_SC_BOTTOM 0x1690
|
||||
|
||||
#define R128_BRUSH_DATA0 0x1480
|
||||
#define R128_BUS_CNTL 0x0030
|
||||
# define R128_BUS_MASTER_DIS (1 << 6)
|
||||
|
||||
#define R128_CLOCK_CNTL_INDEX 0x0008
|
||||
#define R128_CLOCK_CNTL_DATA 0x000c
|
||||
# define R128_PLL_WR_EN (1 << 7)
|
||||
#define R128_CONSTANT_COLOR_C 0x1d34
|
||||
#define R128_CRTC_OFFSET 0x0224
|
||||
#define R128_CRTC_OFFSET_CNTL 0x0228
|
||||
# define R128_CRTC_OFFSET_FLIP_CNTL (1 << 16)
|
||||
|
||||
#define R128_DP_GUI_MASTER_CNTL 0x146c
|
||||
# define R128_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0)
|
||||
# define R128_GMC_DST_PITCH_OFFSET_CNTL (1 << 1)
|
||||
# define R128_GMC_BRUSH_SOLID_COLOR (13 << 4)
|
||||
# define R128_GMC_BRUSH_NONE (15 << 4)
|
||||
# define R128_GMC_DST_16BPP (4 << 8)
|
||||
# define R128_GMC_DST_24BPP (5 << 8)
|
||||
# define R128_GMC_DST_32BPP (6 << 8)
|
||||
# define R128_GMC_DST_DATATYPE_SHIFT 8
|
||||
# define R128_GMC_SRC_DATATYPE_COLOR (3 << 12)
|
||||
# define R128_DP_SRC_SOURCE_MEMORY (2 << 24)
|
||||
# define R128_DP_SRC_SOURCE_HOST_DATA (3 << 24)
|
||||
# define R128_GMC_CLR_CMP_CNTL_DIS (1 << 28)
|
||||
# define R128_GMC_AUX_CLIP_DIS (1 << 29)
|
||||
# define R128_GMC_WR_MSK_DIS (1 << 30)
|
||||
# define R128_ROP3_S 0x00cc0000
|
||||
# define R128_ROP3_P 0x00f00000
|
||||
#define R128_DP_WRITE_MASK 0x16cc
|
||||
#define R128_DST_PITCH_OFFSET_C 0x1c80
|
||||
# define R128_DST_TILE (1 << 31)
|
||||
|
||||
#define R128_GEN_INT_CNTL 0x0040
|
||||
# define R128_CRTC_VBLANK_INT_EN (1 << 0)
|
||||
#define R128_GEN_INT_STATUS 0x0044
|
||||
# define R128_CRTC_VBLANK_INT (1 << 0)
|
||||
# define R128_CRTC_VBLANK_INT_AK (1 << 0)
|
||||
#define R128_GEN_RESET_CNTL 0x00f0
|
||||
# define R128_SOFT_RESET_GUI (1 << 0)
|
||||
|
||||
#define R128_GUI_SCRATCH_REG0 0x15e0
|
||||
#define R128_GUI_SCRATCH_REG1 0x15e4
|
||||
#define R128_GUI_SCRATCH_REG2 0x15e8
|
||||
#define R128_GUI_SCRATCH_REG3 0x15ec
|
||||
#define R128_GUI_SCRATCH_REG4 0x15f0
|
||||
#define R128_GUI_SCRATCH_REG5 0x15f4
|
||||
|
||||
#define R128_GUI_STAT 0x1740
|
||||
# define R128_GUI_FIFOCNT_MASK 0x0fff
|
||||
# define R128_GUI_ACTIVE (1 << 31)
|
||||
|
||||
#define R128_MCLK_CNTL 0x000f
|
||||
# define R128_FORCE_GCP (1 << 16)
|
||||
# define R128_FORCE_PIPE3D_CP (1 << 17)
|
||||
# define R128_FORCE_RCP (1 << 18)
|
||||
|
||||
#define R128_PC_GUI_CTLSTAT 0x1748
|
||||
#define R128_PC_NGUI_CTLSTAT 0x0184
|
||||
# define R128_PC_FLUSH_GUI (3 << 0)
|
||||
# define R128_PC_RI_GUI (1 << 2)
|
||||
# define R128_PC_FLUSH_ALL 0x00ff
|
||||
# define R128_PC_BUSY (1 << 31)
|
||||
|
||||
#define R128_PCI_GART_PAGE 0x017c
|
||||
#define R128_PRIM_TEX_CNTL_C 0x1cb0
|
||||
|
||||
#define R128_SCALE_3D_CNTL 0x1a00
|
||||
#define R128_SEC_TEX_CNTL_C 0x1d00
|
||||
#define R128_SEC_TEXTURE_BORDER_COLOR_C 0x1d3c
|
||||
#define R128_SETUP_CNTL 0x1bc4
|
||||
#define R128_STEN_REF_MASK_C 0x1d40
|
||||
|
||||
#define R128_TEX_CNTL_C 0x1c9c
|
||||
# define R128_TEX_CACHE_FLUSH (1 << 23)
|
||||
|
||||
#define R128_WAIT_UNTIL 0x1720
|
||||
# define R128_EVENT_CRTC_OFFSET (1 << 0)
|
||||
#define R128_WINDOW_XY_OFFSET 0x1bcc
|
||||
|
||||
/* CCE registers
|
||||
*/
|
||||
#define R128_PM4_BUFFER_OFFSET 0x0700
|
||||
#define R128_PM4_BUFFER_CNTL 0x0704
|
||||
# define R128_PM4_MASK (15 << 28)
|
||||
# define R128_PM4_NONPM4 (0 << 28)
|
||||
# define R128_PM4_192PIO (1 << 28)
|
||||
# define R128_PM4_192BM (2 << 28)
|
||||
# define R128_PM4_128PIO_64INDBM (3 << 28)
|
||||
# define R128_PM4_128BM_64INDBM (4 << 28)
|
||||
# define R128_PM4_64PIO_128INDBM (5 << 28)
|
||||
# define R128_PM4_64BM_128INDBM (6 << 28)
|
||||
# define R128_PM4_64PIO_64VCBM_64INDBM (7 << 28)
|
||||
# define R128_PM4_64BM_64VCBM_64INDBM (8 << 28)
|
||||
# define R128_PM4_64PIO_64VCPIO_64INDPIO (15 << 28)
|
||||
# define R128_PM4_BUFFER_CNTL_NOUPDATE (1 << 27)
|
||||
|
||||
#define R128_PM4_BUFFER_WM_CNTL 0x0708
|
||||
# define R128_WMA_SHIFT 0
|
||||
# define R128_WMB_SHIFT 8
|
||||
# define R128_WMC_SHIFT 16
|
||||
# define R128_WB_WM_SHIFT 24
|
||||
|
||||
#define R128_PM4_BUFFER_DL_RPTR_ADDR 0x070c
|
||||
#define R128_PM4_BUFFER_DL_RPTR 0x0710
|
||||
#define R128_PM4_BUFFER_DL_WPTR 0x0714
|
||||
# define R128_PM4_BUFFER_DL_DONE (1 << 31)
|
||||
|
||||
#define R128_PM4_VC_FPU_SETUP 0x071c
|
||||
|
||||
#define R128_PM4_IW_INDOFF 0x0738
|
||||
#define R128_PM4_IW_INDSIZE 0x073c
|
||||
|
||||
#define R128_PM4_STAT 0x07b8
|
||||
# define R128_PM4_FIFOCNT_MASK 0x0fff
|
||||
# define R128_PM4_BUSY (1 << 16)
|
||||
# define R128_PM4_GUI_ACTIVE (1 << 31)
|
||||
|
||||
#define R128_PM4_MICROCODE_ADDR 0x07d4
|
||||
#define R128_PM4_MICROCODE_RADDR 0x07d8
|
||||
#define R128_PM4_MICROCODE_DATAH 0x07dc
|
||||
#define R128_PM4_MICROCODE_DATAL 0x07e0
|
||||
|
||||
#define R128_PM4_BUFFER_ADDR 0x07f0
|
||||
#define R128_PM4_MICRO_CNTL 0x07fc
|
||||
# define R128_PM4_MICRO_FREERUN (1 << 30)
|
||||
|
||||
#define R128_PM4_FIFO_DATA_EVEN 0x1000
|
||||
#define R128_PM4_FIFO_DATA_ODD 0x1004
|
||||
|
||||
/* CCE command packets
|
||||
*/
|
||||
#define R128_CCE_PACKET0 0x00000000
|
||||
#define R128_CCE_PACKET1 0x40000000
|
||||
#define R128_CCE_PACKET2 0x80000000
|
||||
#define R128_CCE_PACKET3 0xC0000000
|
||||
# define R128_CNTL_HOSTDATA_BLT 0x00009400
|
||||
# define R128_CNTL_PAINT_MULTI 0x00009A00
|
||||
# define R128_CNTL_BITBLT_MULTI 0x00009B00
|
||||
# define R128_3D_RNDR_GEN_INDX_PRIM 0x00002300
|
||||
|
||||
#define R128_CCE_PACKET_MASK 0xC0000000
|
||||
#define R128_CCE_PACKET_COUNT_MASK 0x3fff0000
|
||||
#define R128_CCE_PACKET0_REG_MASK 0x000007ff
|
||||
#define R128_CCE_PACKET1_REG0_MASK 0x000007ff
|
||||
#define R128_CCE_PACKET1_REG1_MASK 0x003ff800
|
||||
|
||||
#define R128_CCE_VC_CNTL_PRIM_TYPE_NONE 0x00000000
|
||||
#define R128_CCE_VC_CNTL_PRIM_TYPE_POINT 0x00000001
|
||||
#define R128_CCE_VC_CNTL_PRIM_TYPE_LINE 0x00000002
|
||||
#define R128_CCE_VC_CNTL_PRIM_TYPE_POLY_LINE 0x00000003
|
||||
#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST 0x00000004
|
||||
#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_FAN 0x00000005
|
||||
#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_STRIP 0x00000006
|
||||
#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2 0x00000007
|
||||
#define R128_CCE_VC_CNTL_PRIM_WALK_IND 0x00000010
|
||||
#define R128_CCE_VC_CNTL_PRIM_WALK_LIST 0x00000020
|
||||
#define R128_CCE_VC_CNTL_PRIM_WALK_RING 0x00000030
|
||||
#define R128_CCE_VC_CNTL_NUM_SHIFT 16
|
||||
|
||||
#define R128_DATATYPE_VQ 0
|
||||
#define R128_DATATYPE_CI4 1
|
||||
#define R128_DATATYPE_CI8 2
|
||||
#define R128_DATATYPE_ARGB1555 3
|
||||
#define R128_DATATYPE_RGB565 4
|
||||
#define R128_DATATYPE_RGB888 5
|
||||
#define R128_DATATYPE_ARGB8888 6
|
||||
#define R128_DATATYPE_RGB332 7
|
||||
#define R128_DATATYPE_Y8 8
|
||||
#define R128_DATATYPE_RGB8 9
|
||||
#define R128_DATATYPE_CI16 10
|
||||
#define R128_DATATYPE_YVYU422 11
|
||||
#define R128_DATATYPE_VYUY422 12
|
||||
#define R128_DATATYPE_AYUV444 14
|
||||
#define R128_DATATYPE_ARGB4444 15
|
||||
|
||||
/* Constants */
|
||||
#define R128_AGP_OFFSET 0x02000000
|
||||
|
||||
#define R128_WATERMARK_L 16
|
||||
#define R128_WATERMARK_M 8
|
||||
#define R128_WATERMARK_N 8
|
||||
#define R128_WATERMARK_K 128
|
||||
|
||||
#define R128_MAX_USEC_TIMEOUT 100000 /* 100 ms */
|
||||
|
||||
#define R128_LAST_FRAME_REG R128_GUI_SCRATCH_REG0
|
||||
#define R128_LAST_DISPATCH_REG R128_GUI_SCRATCH_REG1
|
||||
#define R128_MAX_VB_AGE 0x7fffffff
|
||||
#define R128_MAX_VB_VERTS (0xffff)
|
||||
|
||||
#define R128_RING_HIGH_MARK 128
|
||||
|
||||
#define R128_PERFORMANCE_BOXES 0
|
||||
|
||||
#define R128_PCIGART_TABLE_SIZE 32768
|
||||
|
||||
#define R128_READ(reg) DRM_READ32(dev_priv->mmio, (reg))
|
||||
#define R128_WRITE(reg, val) DRM_WRITE32(dev_priv->mmio, (reg), (val))
|
||||
#define R128_READ8(reg) DRM_READ8(dev_priv->mmio, (reg))
|
||||
#define R128_WRITE8(reg, val) DRM_WRITE8(dev_priv->mmio, (reg), (val))
|
||||
|
||||
#define R128_WRITE_PLL(addr, val) \
|
||||
do { \
|
||||
R128_WRITE8(R128_CLOCK_CNTL_INDEX, \
|
||||
((addr) & 0x1f) | R128_PLL_WR_EN); \
|
||||
R128_WRITE(R128_CLOCK_CNTL_DATA, (val)); \
|
||||
} while (0)
|
||||
|
||||
#define CCE_PACKET0(reg, n) (R128_CCE_PACKET0 | \
|
||||
((n) << 16) | ((reg) >> 2))
|
||||
#define CCE_PACKET1(reg0, reg1) (R128_CCE_PACKET1 | \
|
||||
(((reg1) >> 2) << 11) | ((reg0) >> 2))
|
||||
#define CCE_PACKET2() (R128_CCE_PACKET2)
|
||||
#define CCE_PACKET3(pkt, n) (R128_CCE_PACKET3 | \
|
||||
(pkt) | ((n) << 16))
|
||||
|
||||
static __inline__ void r128_update_ring_snapshot(drm_r128_private_t *dev_priv)
|
||||
{
|
||||
drm_r128_ring_buffer_t *ring = &dev_priv->ring;
|
||||
ring->space = (GET_RING_HEAD(dev_priv) - ring->tail) * sizeof(u32);
|
||||
if (ring->space <= 0)
|
||||
ring->space += ring->size;
|
||||
}
|
||||
|
||||
/* ================================================================
|
||||
* Misc helper macros
|
||||
*/
|
||||
|
||||
#define DEV_INIT_TEST_WITH_RETURN(_dev_priv) \
|
||||
do { \
|
||||
if (!_dev_priv) { \
|
||||
DRM_ERROR("called with no initialization\n"); \
|
||||
return -EINVAL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define RING_SPACE_TEST_WITH_RETURN(dev_priv) \
|
||||
do { \
|
||||
drm_r128_ring_buffer_t *ring = &dev_priv->ring; int i; \
|
||||
if (ring->space < ring->high_mark) { \
|
||||
for (i = 0 ; i < dev_priv->usec_timeout ; i++) { \
|
||||
r128_update_ring_snapshot(dev_priv); \
|
||||
if (ring->space >= ring->high_mark) \
|
||||
goto __ring_space_done; \
|
||||
DRM_UDELAY(1); \
|
||||
} \
|
||||
DRM_ERROR("ring space check failed!\n"); \
|
||||
return -EBUSY; \
|
||||
} \
|
||||
__ring_space_done: \
|
||||
; \
|
||||
} while (0)
|
||||
|
||||
#define VB_AGE_TEST_WITH_RETURN(dev_priv) \
|
||||
do { \
|
||||
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; \
|
||||
if (sarea_priv->last_dispatch >= R128_MAX_VB_AGE) { \
|
||||
int __ret = r128_do_cce_idle(dev_priv); \
|
||||
if (__ret) \
|
||||
return __ret; \
|
||||
sarea_priv->last_dispatch = 0; \
|
||||
r128_freelist_reset(dev); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define R128_WAIT_UNTIL_PAGE_FLIPPED() do { \
|
||||
OUT_RING(CCE_PACKET0(R128_WAIT_UNTIL, 0)); \
|
||||
OUT_RING(R128_EVENT_CRTC_OFFSET); \
|
||||
} while (0)
|
||||
|
||||
/* ================================================================
|
||||
* Ring control
|
||||
*/
|
||||
|
||||
#define R128_VERBOSE 0
|
||||
|
||||
#define RING_LOCALS \
|
||||
int write, _nr; unsigned int tail_mask; volatile u32 *ring;
|
||||
|
||||
#define BEGIN_RING(n) do { \
|
||||
if (R128_VERBOSE) \
|
||||
DRM_INFO("BEGIN_RING(%d)\n", (n)); \
|
||||
if (dev_priv->ring.space <= (n) * sizeof(u32)) { \
|
||||
COMMIT_RING(); \
|
||||
r128_wait_ring(dev_priv, (n) * sizeof(u32)); \
|
||||
} \
|
||||
_nr = n; dev_priv->ring.space -= (n) * sizeof(u32); \
|
||||
ring = dev_priv->ring.start; \
|
||||
write = dev_priv->ring.tail; \
|
||||
tail_mask = dev_priv->ring.tail_mask; \
|
||||
} while (0)
|
||||
|
||||
/* You can set this to zero if you want. If the card locks up, you'll
|
||||
* need to keep this set. It works around a bug in early revs of the
|
||||
* Rage 128 chipset, where the CCE would read 32 dwords past the end of
|
||||
* the ring buffer before wrapping around.
|
||||
*/
|
||||
#define R128_BROKEN_CCE 1
|
||||
|
||||
#define ADVANCE_RING() do { \
|
||||
if (R128_VERBOSE) \
|
||||
DRM_INFO("ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \
|
||||
write, dev_priv->ring.tail); \
|
||||
if (R128_BROKEN_CCE && write < 32) \
|
||||
memcpy(dev_priv->ring.end, \
|
||||
dev_priv->ring.start, \
|
||||
write * sizeof(u32)); \
|
||||
if (((dev_priv->ring.tail + _nr) & tail_mask) != write) \
|
||||
DRM_ERROR( \
|
||||
"ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n", \
|
||||
((dev_priv->ring.tail + _nr) & tail_mask), \
|
||||
write, __LINE__); \
|
||||
else \
|
||||
dev_priv->ring.tail = write; \
|
||||
} while (0)
|
||||
|
||||
#define COMMIT_RING() do { \
|
||||
if (R128_VERBOSE) \
|
||||
DRM_INFO("COMMIT_RING() tail=0x%06x\n", \
|
||||
dev_priv->ring.tail); \
|
||||
mb(); \
|
||||
R128_WRITE(R128_PM4_BUFFER_DL_WPTR, dev_priv->ring.tail); \
|
||||
R128_READ(R128_PM4_BUFFER_DL_WPTR); \
|
||||
} while (0)
|
||||
|
||||
#define OUT_RING(x) do { \
|
||||
if (R128_VERBOSE) \
|
||||
DRM_INFO(" OUT_RING( 0x%08x ) at 0x%x\n", \
|
||||
(unsigned int)(x), write); \
|
||||
ring[write++] = cpu_to_le32(x); \
|
||||
write &= tail_mask; \
|
||||
} while (0)
|
||||
|
||||
#endif /* __R128_DRV_H__ */
|
215
drivers/gpu/drm/r128/r128_ioc32.c
Normal file
215
drivers/gpu/drm/r128/r128_ioc32.c
Normal file
|
@ -0,0 +1,215 @@
|
|||
/**
|
||||
* \file r128_ioc32.c
|
||||
*
|
||||
* 32-bit ioctl compatibility routines for the R128 DRM.
|
||||
*
|
||||
* \author Dave Airlie <airlied@linux.ie> with code from patches by Egbert Eich
|
||||
*
|
||||
* Copyright (C) Paul Mackerras 2005
|
||||
* Copyright (C) Egbert Eich 2003,2004
|
||||
* Copyright (C) Dave Airlie 2005
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
#include <linux/compat.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/r128_drm.h>
|
||||
#include "r128_drv.h"
|
||||
|
||||
typedef struct drm_r128_init32 {
|
||||
int func;
|
||||
unsigned int sarea_priv_offset;
|
||||
int is_pci;
|
||||
int cce_mode;
|
||||
int cce_secure;
|
||||
int ring_size;
|
||||
int usec_timeout;
|
||||
|
||||
unsigned int fb_bpp;
|
||||
unsigned int front_offset, front_pitch;
|
||||
unsigned int back_offset, back_pitch;
|
||||
unsigned int depth_bpp;
|
||||
unsigned int depth_offset, depth_pitch;
|
||||
unsigned int span_offset;
|
||||
|
||||
unsigned int fb_offset;
|
||||
unsigned int mmio_offset;
|
||||
unsigned int ring_offset;
|
||||
unsigned int ring_rptr_offset;
|
||||
unsigned int buffers_offset;
|
||||
unsigned int agp_textures_offset;
|
||||
} drm_r128_init32_t;
|
||||
|
||||
static int compat_r128_init(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_r128_init32_t init32;
|
||||
drm_r128_init_t __user *init;
|
||||
|
||||
if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
|
||||
return -EFAULT;
|
||||
|
||||
init = compat_alloc_user_space(sizeof(*init));
|
||||
if (!access_ok(VERIFY_WRITE, init, sizeof(*init))
|
||||
|| __put_user(init32.func, &init->func)
|
||||
|| __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset)
|
||||
|| __put_user(init32.is_pci, &init->is_pci)
|
||||
|| __put_user(init32.cce_mode, &init->cce_mode)
|
||||
|| __put_user(init32.cce_secure, &init->cce_secure)
|
||||
|| __put_user(init32.ring_size, &init->ring_size)
|
||||
|| __put_user(init32.usec_timeout, &init->usec_timeout)
|
||||
|| __put_user(init32.fb_bpp, &init->fb_bpp)
|
||||
|| __put_user(init32.front_offset, &init->front_offset)
|
||||
|| __put_user(init32.front_pitch, &init->front_pitch)
|
||||
|| __put_user(init32.back_offset, &init->back_offset)
|
||||
|| __put_user(init32.back_pitch, &init->back_pitch)
|
||||
|| __put_user(init32.depth_bpp, &init->depth_bpp)
|
||||
|| __put_user(init32.depth_offset, &init->depth_offset)
|
||||
|| __put_user(init32.depth_pitch, &init->depth_pitch)
|
||||
|| __put_user(init32.span_offset, &init->span_offset)
|
||||
|| __put_user(init32.fb_offset, &init->fb_offset)
|
||||
|| __put_user(init32.mmio_offset, &init->mmio_offset)
|
||||
|| __put_user(init32.ring_offset, &init->ring_offset)
|
||||
|| __put_user(init32.ring_rptr_offset, &init->ring_rptr_offset)
|
||||
|| __put_user(init32.buffers_offset, &init->buffers_offset)
|
||||
|| __put_user(init32.agp_textures_offset,
|
||||
&init->agp_textures_offset))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file, DRM_IOCTL_R128_INIT, (unsigned long)init);
|
||||
}
|
||||
|
||||
typedef struct drm_r128_depth32 {
|
||||
int func;
|
||||
int n;
|
||||
u32 x;
|
||||
u32 y;
|
||||
u32 buffer;
|
||||
u32 mask;
|
||||
} drm_r128_depth32_t;
|
||||
|
||||
static int compat_r128_depth(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_r128_depth32_t depth32;
|
||||
drm_r128_depth_t __user *depth;
|
||||
|
||||
if (copy_from_user(&depth32, (void __user *)arg, sizeof(depth32)))
|
||||
return -EFAULT;
|
||||
|
||||
depth = compat_alloc_user_space(sizeof(*depth));
|
||||
if (!access_ok(VERIFY_WRITE, depth, sizeof(*depth))
|
||||
|| __put_user(depth32.func, &depth->func)
|
||||
|| __put_user(depth32.n, &depth->n)
|
||||
|| __put_user((int __user *)(unsigned long)depth32.x, &depth->x)
|
||||
|| __put_user((int __user *)(unsigned long)depth32.y, &depth->y)
|
||||
|| __put_user((unsigned int __user *)(unsigned long)depth32.buffer,
|
||||
&depth->buffer)
|
||||
|| __put_user((unsigned char __user *)(unsigned long)depth32.mask,
|
||||
&depth->mask))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file, DRM_IOCTL_R128_DEPTH, (unsigned long)depth);
|
||||
|
||||
}
|
||||
|
||||
typedef struct drm_r128_stipple32 {
|
||||
u32 mask;
|
||||
} drm_r128_stipple32_t;
|
||||
|
||||
static int compat_r128_stipple(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_r128_stipple32_t stipple32;
|
||||
drm_r128_stipple_t __user *stipple;
|
||||
|
||||
if (copy_from_user(&stipple32, (void __user *)arg, sizeof(stipple32)))
|
||||
return -EFAULT;
|
||||
|
||||
stipple = compat_alloc_user_space(sizeof(*stipple));
|
||||
if (!access_ok(VERIFY_WRITE, stipple, sizeof(*stipple))
|
||||
|| __put_user((unsigned int __user *)(unsigned long)stipple32.mask,
|
||||
&stipple->mask))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file, DRM_IOCTL_R128_STIPPLE, (unsigned long)stipple);
|
||||
}
|
||||
|
||||
typedef struct drm_r128_getparam32 {
|
||||
int param;
|
||||
u32 value;
|
||||
} drm_r128_getparam32_t;
|
||||
|
||||
static int compat_r128_getparam(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
drm_r128_getparam32_t getparam32;
|
||||
drm_r128_getparam_t __user *getparam;
|
||||
|
||||
if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32)))
|
||||
return -EFAULT;
|
||||
|
||||
getparam = compat_alloc_user_space(sizeof(*getparam));
|
||||
if (!access_ok(VERIFY_WRITE, getparam, sizeof(*getparam))
|
||||
|| __put_user(getparam32.param, &getparam->param)
|
||||
|| __put_user((void __user *)(unsigned long)getparam32.value,
|
||||
&getparam->value))
|
||||
return -EFAULT;
|
||||
|
||||
return drm_ioctl(file, DRM_IOCTL_R128_GETPARAM, (unsigned long)getparam);
|
||||
}
|
||||
|
||||
drm_ioctl_compat_t *r128_compat_ioctls[] = {
|
||||
[DRM_R128_INIT] = compat_r128_init,
|
||||
[DRM_R128_DEPTH] = compat_r128_depth,
|
||||
[DRM_R128_STIPPLE] = compat_r128_stipple,
|
||||
[DRM_R128_GETPARAM] = compat_r128_getparam,
|
||||
};
|
||||
|
||||
/**
|
||||
* Called whenever a 32-bit process running under a 64-bit kernel
|
||||
* performs an ioctl on /dev/dri/card<n>.
|
||||
*
|
||||
* \param filp file pointer.
|
||||
* \param cmd command.
|
||||
* \param arg user argument.
|
||||
* \return zero on success or negative number on failure.
|
||||
*/
|
||||
long r128_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned int nr = DRM_IOCTL_NR(cmd);
|
||||
drm_ioctl_compat_t *fn = NULL;
|
||||
int ret;
|
||||
|
||||
if (nr < DRM_COMMAND_BASE)
|
||||
return drm_compat_ioctl(filp, cmd, arg);
|
||||
|
||||
if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(r128_compat_ioctls))
|
||||
fn = r128_compat_ioctls[nr - DRM_COMMAND_BASE];
|
||||
|
||||
if (fn != NULL)
|
||||
ret = (*fn) (filp, cmd, arg);
|
||||
else
|
||||
ret = drm_ioctl(filp, cmd, arg);
|
||||
|
||||
return ret;
|
||||
}
|
115
drivers/gpu/drm/r128/r128_irq.c
Normal file
115
drivers/gpu/drm/r128/r128_irq.c
Normal file
|
@ -0,0 +1,115 @@
|
|||
/* r128_irq.c -- IRQ handling for radeon -*- linux-c -*- */
|
||||
/*
|
||||
* Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved.
|
||||
*
|
||||
* The Weather Channel (TM) funded Tungsten Graphics to develop the
|
||||
* initial release of the Radeon 8500 driver under the XFree86 license.
|
||||
* This notice must be preserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Keith Whitwell <keith@tungstengraphics.com>
|
||||
* Eric Anholt <anholt@FreeBSD.org>
|
||||
*/
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/r128_drm.h>
|
||||
#include "r128_drv.h"
|
||||
|
||||
u32 r128_get_vblank_counter(struct drm_device *dev, int crtc)
|
||||
{
|
||||
const drm_r128_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
if (crtc != 0)
|
||||
return 0;
|
||||
|
||||
return atomic_read(&dev_priv->vbl_received);
|
||||
}
|
||||
|
||||
irqreturn_t r128_driver_irq_handler(int irq, void *arg)
|
||||
{
|
||||
struct drm_device *dev = (struct drm_device *) arg;
|
||||
drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
|
||||
int status;
|
||||
|
||||
status = R128_READ(R128_GEN_INT_STATUS);
|
||||
|
||||
/* VBLANK interrupt */
|
||||
if (status & R128_CRTC_VBLANK_INT) {
|
||||
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
|
||||
atomic_inc(&dev_priv->vbl_received);
|
||||
drm_handle_vblank(dev, 0);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
int r128_enable_vblank(struct drm_device *dev, int crtc)
|
||||
{
|
||||
drm_r128_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
if (crtc != 0) {
|
||||
DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void r128_disable_vblank(struct drm_device *dev, int crtc)
|
||||
{
|
||||
if (crtc != 0)
|
||||
DRM_ERROR("%s: bad crtc %d\n", __func__, crtc);
|
||||
|
||||
/*
|
||||
* FIXME: implement proper interrupt disable by using the vblank
|
||||
* counter register (if available)
|
||||
*
|
||||
* R128_WRITE(R128_GEN_INT_CNTL,
|
||||
* R128_READ(R128_GEN_INT_CNTL) & ~R128_CRTC_VBLANK_INT_EN);
|
||||
*/
|
||||
}
|
||||
|
||||
void r128_driver_irq_preinstall(struct drm_device *dev)
|
||||
{
|
||||
drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
|
||||
|
||||
/* Disable *all* interrupts */
|
||||
R128_WRITE(R128_GEN_INT_CNTL, 0);
|
||||
/* Clear vblank bit if it's already high */
|
||||
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
|
||||
}
|
||||
|
||||
int r128_driver_irq_postinstall(struct drm_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void r128_driver_irq_uninstall(struct drm_device *dev)
|
||||
{
|
||||
drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
|
||||
if (!dev_priv)
|
||||
return;
|
||||
|
||||
/* Disable *all* interrupts */
|
||||
R128_WRITE(R128_GEN_INT_CNTL, 0);
|
||||
}
|
1644
drivers/gpu/drm/r128/r128_state.c
Normal file
1644
drivers/gpu/drm/r128/r128_state.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue