diff options
author | Keith Whitwell <keith@tungstengraphics.com> | 2000-02-04 07:32:24 +0000 |
---|---|---|
committer | Keith Whitwell <keith@tungstengraphics.com> | 2000-02-04 07:32:24 +0000 |
commit | 4db40c2a8b53b1e02e6607fb301a5ca886d461ce (patch) | |
tree | 8dd6a9b392ddf609a9e3b76e21e6eb49d833844f | |
parent | 484f610fb1abe449968e796a652b5834b6b95bee (diff) |
Added code for swapbuffers and clearbuffers.
Added code to emit all driver state, including context, texture and warp
states.
Added a hack for carrying state along with a dma buffer. Hopefully Jeff
will have a better solution for this problem.
-rw-r--r-- | linux-core/drmP.h | 14 | ||||
-rw-r--r-- | linux-core/mga_drv.c | 2 | ||||
-rw-r--r-- | linux/Makefile.linux | 4 | ||||
-rw-r--r-- | linux/drm.h | 4 | ||||
-rw-r--r-- | linux/drmP.h | 14 | ||||
-rw-r--r-- | linux/mga_clear.c | 203 | ||||
-rw-r--r-- | linux/mga_dma.c | 202 | ||||
-rw-r--r-- | linux/mga_dma.h | 57 | ||||
-rw-r--r-- | linux/mga_drm_public.h | 217 | ||||
-rw-r--r-- | linux/mga_drv.c | 2 | ||||
-rw-r--r-- | linux/mga_drv.h | 17 | ||||
-rw-r--r-- | linux/mga_state.c | 442 | ||||
-rw-r--r-- | shared-core/drm.h | 4 | ||||
-rw-r--r-- | shared/drm.h | 4 |
14 files changed, 882 insertions, 304 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 97d2539a..5bbf1bfe 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -260,14 +260,12 @@ typedef struct drm_buf { DRM_LIST_PRIO = 4, DRM_LIST_RECLAIM = 5 } list; /* Which list we're on */ -#if 0 - enum { - TT_GENERAL, - TT_BLIT, - TT_VECTOR, - TT_VERTEX - } transfer_type; -#endif + + + int type; /* push into dev_priv? */ + void *dev_priv; + + #if DRM_DMA_HISTOGRAM cycles_t time_queued; /* Queued to kernel DMA queue */ cycles_t time_dispatched; /* Dispatched to hardware */ diff --git a/linux-core/mga_drv.c b/linux-core/mga_drv.c index 81c08e81..60cf9b1d 100644 --- a/linux-core/mga_drv.c +++ b/linux-core/mga_drv.c @@ -259,7 +259,7 @@ static int mga_takedown(drm_device_t *dev) drm_agp_mem_t *nexte; /* Remove AGP resources, but leave dev->agp - intact until r128_cleanup is called. */ + intact until cleanup is called. */ for (entry = dev->agp->memory; entry; entry = nexte) { nexte = entry->next; if (entry->bound) drm_unbind_agp(entry->memory); diff --git a/linux/Makefile.linux b/linux/Makefile.linux index c95ec17d..c0ab34ab 100644 --- a/linux/Makefile.linux +++ b/linux/Makefile.linux @@ -71,8 +71,8 @@ GAMMAHEADERS= gamma_drv.h $(DRMHEADERS) TDFXOBJS= tdfx_drv.o tdfx_context.o TDFXHEADERS= tdfx_drv.h $(DRMHEADERS) -MGAOBJS= mga_drv.o mga_dma.o mga_bufs.o -MGAHEADERS= mga_drv.h $(DRMHEADERS) +MGAOBJS= mga_drv.o mga_dma.o mga_bufs.o mga_state.o mga_clear.o +MGAHEADERS= mga_drv.h mga_drm_public.h $(DRMHEADERS) R128OBJS= r128_drv.o r128_context.o R128HEADERS= r128_drv.h $(DRMHEADERS) diff --git a/linux/drm.h b/linux/drm.h index 01b2024c..01c5bdc8 100644 --- a/linux/drm.h +++ b/linux/drm.h @@ -162,9 +162,11 @@ typedef enum drm_dma_flags { /* These values *MUST* match xf86drm.h */ _DRM_DMA_LARGER_OK = 0x40, /* Larger-than-requested buffers ok */ /* Specially for MGA, but not limited to use by it */ + _DRM_DMA_TYPE_MASK = 0x0F000000, + _DRM_DMA_GENERAL = 0x00000000, /* the default type */ _DRM_DMA_VERTEX = 0x01000000, _DRM_DMA_SETUP = 0x02000000, - _DRM_DMA_BLIT = 0x04000000 + _DRM_DMA_BLIT = 0x03000000 } drm_dma_flags_t; typedef struct drm_buf_desc { diff --git a/linux/drmP.h b/linux/drmP.h index 97d2539a..5bbf1bfe 100644 --- a/linux/drmP.h +++ b/linux/drmP.h @@ -260,14 +260,12 @@ typedef struct drm_buf { DRM_LIST_PRIO = 4, DRM_LIST_RECLAIM = 5 } list; /* Which list we're on */ -#if 0 - enum { - TT_GENERAL, - TT_BLIT, - TT_VECTOR, - TT_VERTEX - } transfer_type; -#endif + + + int type; /* push into dev_priv? */ + void *dev_priv; + + #if DRM_DMA_HISTOGRAM cycles_t time_queued; /* Queued to kernel DMA queue */ cycles_t time_dispatched; /* Dispatched to hardware */ diff --git a/linux/mga_clear.c b/linux/mga_clear.c new file mode 100644 index 00000000..8dfcac42 --- /dev/null +++ b/linux/mga_clear.c @@ -0,0 +1,203 @@ +/* mga_state.c -- State support for mga g200/g400 -*- linux-c -*- + * + * Created: February 2000 by keithw@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * 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: + * Keith Whitwell <keithw@precisioninsight.com> + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "mga_drv.h" +#include "mgareg_flags.h" +#include "mga_dma.h" + +#define MGA_CLEAR_CMD (DC_opcod_trap | DC_arzero_enable | \ + DC_sgnzero_enable | DC_shftzero_enable | \ + (0xC << DC_bop_SHIFT) | DC_clipdis_enable | \ + DC_solid_enable | DC_transc_enable) + + +#define MGA_COPY_CMD (DC_opcod_bitblt | DC_atype_rpl | DC_linear_xy | \ + DC_solid_disable | DC_arzero_disable | \ + DC_sgnzero_enable | DC_shftzero_enable | \ + (0xC << DC_bop_SHIFT) | DC_bltmod_bfcol | \ + DC_pattern_disable | DC_transc_disable | \ + DC_clipdis_enable) \ + + +void mgaClearBuffers( drm_device_t *dev, + int clear_color, + int clear_depth, + int flags ) +{ + int cmd, i; + drm_device_dma_t *dma = dev->dma; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + xf86drmClipRectRec *pbox = sarea_priv->boxes; + int nbox = sarea_priv->nbox; + drm_buf_t *buf; + drm_dma_t d; + int order = 10; /* ??? */ + DMALOCALS; + + + if (!nbox) + return; + + if ( dev_priv->sgram ) + cmd = MGA_CLEAR_CMD | DC_atype_blk; + else + cmd = MGA_CLEAR_CMD | DC_atype_rstr; + + buf = drm_freelist_get(&dma->bufs[order].freelist, _DRM_DMA_WAIT); + + + DMAGETPTR( buf ); + + for (i = 0 ; i < nbox ; i++) { + unsigned int height = pbox[i].y2 - pbox[i].y1; + + /* Is it necessary to be this paranoid? I don't think so. + if (pbox[i].x1 > dev_priv->width) continue; + if (pbox[i].y1 > dev_priv->height) continue; + if (pbox[i].x2 > dev_priv->width) continue; + if (pbox[i].y2 > dev_priv->height) continue; + if (pbox[i].x2 <= pbox[i].x1) continue; + if (pbox[i].y2 <= pbox[i].x1) continue; + */ + + DMAOUTREG(MGAREG_YDSTLEN, (pbox[i].y1<<16)|height); + DMAOUTREG(MGAREG_FXBNDRY, (pbox[i].x2<<16)|pbox[i].x1); + + if ( flags & MGA_CLEAR_FRONTBUFFER ) { + DMAOUTREG(MGAREG_FCOL, clear_color); + DMAOUTREG(MGAREG_DSTORG, dev_priv->frontOrg); + DMAOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); + } + + if ( flags & MGA_CLEAR_BACKBUFFER ) { + DMAOUTREG(MGAREG_FCOL, clear_color); + DMAOUTREG(MGAREG_DSTORG, dev_priv->backOrg); + DMAOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); + } + + if ( flags & MGA_CLEAR_DEPTHBUFFER ) + { + DMAOUTREG(MGAREG_FCOL, clear_depth); + DMAOUTREG(MGAREG_DSTORG, dev_priv->depthOrg); + DMAOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC, cmd ); + } + } + + DMAADVANCE( buf ); + + /* Make sure we restore the 3D state next time. + */ + sarea_priv->dirty |= MGASAREA_NEW_CONTEXT; + + d.context = DRM_KERNEL_CONTEXT; + d.send_count = 1; + d.send_indices = &buf->idx; + d.send_sizes = &buf->used; + d.flags = _DRM_DMA_GENERAL; + d.request_count = 0; + d.request_size = 0; + d.request_indices = NULL; + d.request_sizes = NULL; + d.granted_count = 0; + + drm_dma_enqueue(dev, &d); +} + + +void mgaSwapBuffers( drm_device_t *dev ) +{ + drm_device_dma_t *dma = dev->dma; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + xf86drmClipRectRec *pbox = sarea_priv->boxes; + int nbox = sarea_priv->nbox; + drm_buf_t *buf; + drm_dma_t d; + int order = 10; /* ??? */ + int i; + DMALOCALS; + + if (!nbox) + return; + + buf = drm_freelist_get(&dma->bufs[order].freelist, _DRM_DMA_WAIT); + + DMAGETPTR( buf ); + + DMAOUTREG(MGAREG_DSTORG, dev_priv->frontOrg); + DMAOUTREG(MGAREG_MACCESS, dev_priv->mAccess); + DMAOUTREG(MGAREG_SRCORG, dev_priv->backOrg); + DMAOUTREG(MGAREG_AR5, dev_priv->stride); /* unnecessary? */ + DMAOUTREG(MGAREG_DWGCTL, MGA_COPY_CMD); + + for (i = 0 ; i < nbox; i++) { + unsigned int h = pbox[i].y2 - pbox[i].y1; + unsigned int start = pbox[i].y1 * dev_priv->stride; + + /* + if (pbox[i].x1 > dev_priv->width) continue; + if (pbox[i].y1 > dev_priv->height) continue; + if (pbox[i].x2 > dev_priv->width) continue; + if (pbox[i].y2 > dev_priv->height) continue; + if (pbox[i].x2 <= pbox[i].x1) continue; + if (pbox[i].y2 <= pbox[i].x1) continue; + */ + + DMAOUTREG(MGAREG_AR0, start + pbox[i].x2 - 1); + DMAOUTREG(MGAREG_AR3, start + pbox[i].x1); + DMAOUTREG(MGAREG_FXBNDRY, pbox[i].x1|((pbox[i].x2 - 1)<<16)); + DMAOUTREG(MGAREG_YDSTLEN+MGAREG_MGA_EXEC, (pbox[i].y1<<16)|h); + } + + DMAOUTREG(MGAREG_SRCORG, 0); + DMAADVANCE( buf ); + + /* Make sure we restore the 3D state next time. + */ + sarea_priv->dirty |= MGASAREA_NEW_CONTEXT; + + d.context = DRM_KERNEL_CONTEXT; + d.send_count = 1; + d.send_indices = &buf->idx; + d.send_sizes = &buf->used; + d.flags = _DRM_DMA_GENERAL; + d.request_count = 0; + d.request_size = 0; + d.request_indices = NULL; + d.request_sizes = NULL; + d.granted_count = 0; + + drm_dma_enqueue(dev, &d); +} + diff --git a/linux/mga_dma.c b/linux/mga_dma.c index 2c4856ed..e7ac0406 100644 --- a/linux/mga_dma.c +++ b/linux/mga_dma.c @@ -34,6 +34,7 @@ #include "drmP.h" #include "mga_drv.h" #include "mgareg_flags.h" +#include "mga_dma.h" #include <linux/interrupt.h> /* For task queue support */ @@ -45,31 +46,23 @@ #define MGA_READ(reg) MGA_DEREF(reg) #define MGA_WRITE(reg,val) do { MGA_DEREF(reg) = val; } while (0) -#define DWGREG0 0x1c00 -#define DWGREG0_END 0x1dff -#define DWGREG1 0x2c00 -#define DWGREG1_END 0x2dff -#define ISREG0(r) (r >= DWGREG0 && r <= DWGREG0_END) -#define ADRINDEX0(r) (u8)((r - DWGREG0) >> 2) -#define ADRINDEX1(r) (u8)(((r - DWGREG1) >> 2) | 0x80) -#define ADRINDEX(r) (ISREG0(r) ? ADRINDEX0(r) : ADRINDEX1(r)) -#define DMALOCALS() u8 tempIndex[4]; u32 *dma_ptr; u32 phys_head; \ +#define PRIMLOCALS u8 tempIndex[4]; u32 *dma_ptr; u32 phys_head; \ int outcount, num_dwords; unsigned long flags -#define DMAGETPTR() do { \ +#define PRIMGETPTR() do { \ dma_ptr = dev_priv->current_dma_ptr; \ phys_head = dev_priv->prim_phys_head; \ outcount = 0; \ num_dwords = dev_priv->prim_num_dwords; \ } while(0) -#define DMAADVANCE() do { \ +#define PRIMADVANCE() do { \ dev_priv->prim_num_dwords = num_dwords; \ dev_priv->current_dma_ptr = dma_ptr; \ } while(0); -#define DMAOUTREG(reg, val) do { \ +#define PRIMOUTREG(reg, val) do { \ tempIndex[outcount]=ADRINDEX(reg); \ dma_ptr[1+outcount] = val; \ if( ++outcount == 4) { \ @@ -80,7 +73,7 @@ num_dwords += 5; \ } \ }while (0) -#define CHECK_OVERFLOW(length) do { \ +#define PRIM_CHECK_OVERFLOW(length) do { \ if((dev_priv->prim_max_dwords - dev_priv->prim_num_dwords) < \ length) { \ mga_prim_overflow(dev); \ @@ -89,9 +82,6 @@ if((dev_priv->prim_max_dwords - dev_priv->prim_num_dwords) < \ #define PDEA_pagpxfer_enable 0x2 #define MGA_SYNC_TAG 0x423f4200 -#define MGA_YDSTLEN(y,LEN) DMAOUTREG(MGAREG_YDSTLEN,((y) << 16) | (LEN)) -#define MGA_FXBNDRY(x1,x2) DMAOUTREG(MGAREG_FXBNDRY,((x2) << 16) | (x1)) -#define MGA_DWGCTL_EXEC(x) DMAOUTREG(MGAREG_DWGCTL+MGAREG_MGA_EXEC,x) typedef enum { TT_GENERAL, @@ -122,7 +112,7 @@ int mga_dma_cleanup(drm_device_t *dev) int temp; if(dev_priv->ioremap) { - temp = dev_priv->warp_mc_size + dev_priv->primary_size; + temp = dev_priv->warp_ucode_size + dev_priv->primary_size; temp = ((temp + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; drm_ioremapfree((void *) dev_priv->ioremap, temp); @@ -160,8 +150,8 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_private_t *dev_priv, /* Scale primary size to the next page */ dev_priv->primary_size = ((init->primary_size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; - dev_priv->warp_mc_size = init->warp_mc_size; - dev_priv->type = init->type; + dev_priv->warp_ucode_size = init->warp_ucode_size; + dev_priv->chipset = init->chipset; dev_priv->fbOffset = init->fbOffset; dev_priv->backOffset = init->backOffset; dev_priv->depthOffset = init->depthOffset; @@ -177,7 +167,7 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_private_t *dev_priv, printk("memcpy done\n"); prim_map = dev->maplist[init->reserved_map_idx]; dev_priv->prim_phys_head = dev->agp->base + init->reserved_map_agpstart; - temp = init->warp_mc_size + dev_priv->primary_size; + temp = init->warp_ucode_size + dev_priv->primary_size; temp = ((temp + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; printk("temp : %x\n", temp); @@ -199,14 +189,14 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_private_t *dev_priv, printk("dma initialization\n"); /* Private is now filled in, initialize the hardware */ { - DMALOCALS(); + PRIMLOCALS; mga_prim_overflow(dev); - DMAGETPTR(); - DMAOUTREG(MGAREG_DMAPAD, 0); - DMAOUTREG(MGAREG_DMAPAD, 0); - DMAOUTREG(MGAREG_DWGSYNC, 0); - DMAOUTREG(MGAREG_SOFTRAP, 0); - DMAADVANCE(); + PRIMGETPTR(); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DWGSYNC, 0); + PRIMOUTREG(MGAREG_SOFTRAP, 0); + PRIMADVANCE(); /* Poll for the first buffer to insure that * the status register will be correct @@ -258,52 +248,55 @@ int mga_dma_init(struct inode *inode, struct file *filp, return retcode; } -static void mga_dma_dispatch(drm_device_t *dev, unsigned long address, - unsigned long length) + +#define MGA_ILOAD_CMD (DC_opcod_iload | DC_atype_rpl | \ + DC_linear_linear | DC_bltmod_bfcol | \ + (0xC << DC_bop_SHIFT) | DC_sgnzero_enable | \ + DC_shftzero_enable | DC_clipdis_enable) + + +static void mga_dma_dispatch_iload(drm_device_t *dev, unsigned long address, + unsigned long length) { drm_mga_private_t *dev_priv = dev->dev_private; int use_agp = PDEA_pagpxfer_enable; static int j = 0; static int k = 0; int cmd; - DMALOCALS(); - - CHECK_OVERFLOW(20); - DMAGETPTR(); - cmd = DC_opcod_iload | /* image load */ - DC_atype_rpl | /* raster replace mode */ - DC_linear_linear | /* linear source */ - DC_bltmod_bfcol | /* source data is pre-formatted color */ - (0xC << DC_bop_SHIFT) | /* use source bit op */ - DC_sgnzero_enable | /* normal scanning direction */ - DC_shftzero_enable | /* required for iload */ - DC_clipdis_enable; /* don't use the clip rect */ - - MGA_YDSTLEN( k, 512 ); /* top to bottom */ - MGA_FXBNDRY( j, 511+j ); /* full width */ - DMAOUTREG( MGAREG_AR0, 512 * /* source pixel count */ - 512 - 1); - DMAOUTREG( MGAREG_AR3, 0 ); /* required */ - DMAOUTREG( MGAREG_DMAPAD, 0); - DMAOUTREG( MGAREG_DMAPAD, 0); - DMAOUTREG( MGAREG_DMAPAD, 0); - MGA_DWGCTL_EXEC(cmd); - DMAOUTREG(MGAREG_DMAPAD, 0); - DMAOUTREG(MGAREG_DMAPAD, 0); - DMAOUTREG(MGAREG_SECADDRESS, address | TT_BLIT); - DMAOUTREG(MGAREG_SECEND, (address + length) | use_agp); - DMAOUTREG(MGAREG_DMAPAD, 0); - DMAOUTREG(MGAREG_DMAPAD, 0); - DMAOUTREG(MGAREG_DWGSYNC, 0); - DMAOUTREG(MGAREG_SOFTRAP, 0); - DMAADVANCE(); + int y,h,x1,x2; + PRIMLOCALS; + + PRIM_CHECK_OVERFLOW(20); + PRIMGETPTR(); + + y = k; + h = 512; + PRIMOUTREG( MGAREG_YDSTLEN,((y) << 16) | (h)); + + x2 = j + 511; + x1 = j; + PRIMOUTREG( MGAREG_FXBNDRY,((x2) << 16) | (x1)); + + PRIMOUTREG( MGAREG_AR0, 512 * 512 - 1); + PRIMOUTREG( MGAREG_AR3, 0 ); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DWGCTL+MGAREG_MGA_EXEC, MGA_ILOAD_CMD); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_SECADDRESS, address | TT_BLIT); + PRIMOUTREG( MGAREG_SECEND, (address + length) | use_agp); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DWGSYNC, 0); + PRIMOUTREG( MGAREG_SOFTRAP, 0); + PRIMADVANCE(); MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) ; - MGA_WRITE(MGAREG_PRIMEND, (phys_head + - (num_dwords*sizeof(unsigned long))) | - use_agp); + MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); k += 20; j += 5; @@ -311,6 +304,66 @@ static void mga_dma_dispatch(drm_device_t *dev, unsigned long address, if( k < 512) k = 0; } + +static void mga_dma_dispatch_vertex(drm_device_t *dev, unsigned long address, + unsigned long length) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + int use_agp = PDEA_pagpxfer_enable; + PRIMLOCALS; + + PRIM_CHECK_OVERFLOW(20); + PRIMGETPTR(); + + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_SECADDRESS, address | TT_VERTEX); + PRIMOUTREG( MGAREG_SECEND, (address + length) | use_agp); + + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DWGSYNC, 0); + PRIMOUTREG( MGAREG_SOFTRAP, 0); + PRIMADVANCE(); + + MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); + while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) ; + + MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); +} + + +/* Used internally for the small buffers generated from client state + * information. + */ +static void mga_dma_dispatch_general(drm_device_t *dev, unsigned long address, + unsigned long length) +{ + drm_mga_private_t *dev_priv = dev->dev_private; + int use_agp = PDEA_pagpxfer_enable; + PRIMLOCALS; + + PRIM_CHECK_OVERFLOW(20); + PRIMGETPTR(); + + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_SECADDRESS, address | TT_VERTEX); + PRIMOUTREG( MGAREG_SECEND, (address + length) | use_agp); + + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DMAPAD, 0); + PRIMOUTREG( MGAREG_DWGSYNC, 0); + PRIMOUTREG( MGAREG_SOFTRAP, 0); + PRIMADVANCE(); + + MGA_WRITE(MGAREG_DWGSYNC, MGA_SYNC_TAG); + while(MGA_READ(MGAREG_DWGSYNC) != MGA_SYNC_TAG) ; + + MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); +} + + /* Frees dispatch lock */ static inline void mga_dma_quiescent(drm_device_t *dev) { @@ -406,7 +459,6 @@ static void mga_dma_service(int irq, void *device, struct pt_regs *regs) /* Only called by mga_dma_schedule. */ static int mga_do_dma(drm_device_t *dev, int locked) { - unsigned long address; unsigned long length; drm_buf_t *buf; @@ -503,7 +555,27 @@ static int mga_do_dma(drm_device_t *dev, int locked) buf->time_dispatched = get_cycles(); #endif - mga_dma_dispatch(dev, address, length); + + switch (buf->type & _DRM_DMA_TYPE_MASK) { + case _DRM_DMA_GENERAL: + mga_dma_dispatch_general(dev, address, length); + break; + case _DRM_DMA_VERTEX: + mga_dma_dispatch_vertex(dev, address, length); + break; +/* case _DRM_DMA_SETUP: */ +/* mga_dma_dispatch_setup(dev, address, length); */ +/* break; */ + case _DRM_DMA_BLIT: + mga_dma_dispatch_iload(dev, address, length); + break; + default: + printk("bad buffer type %x in dispatch\n", + buf->type & _DRM_DMA_TYPE_MASK); + /* panic? */ + break; + } + drm_free_buffer(dev, dma->this_buffer); dma->this_buffer = buf; diff --git a/linux/mga_dma.h b/linux/mga_dma.h new file mode 100644 index 00000000..6d6d988c --- /dev/null +++ b/linux/mga_dma.h @@ -0,0 +1,57 @@ +#ifndef MGA_DMA_H +#define MGA_DMA_H + + +#define DWGREG0 0x1c00 +#define DWGREG0_END 0x1dff +#define DWGREG1 0x2c00 +#define DWGREG1_END 0x2dff + +#define ISREG0(r) (r >= DWGREG0 && r <= DWGREG0_END) +#define ADRINDEX0(r) (u8)((r - DWGREG0) >> 2) +#define ADRINDEX1(r) (u8)(((r - DWGREG1) >> 2) | 0x80) +#define ADRINDEX(r) (ISREG0(r) ? ADRINDEX0(r) : ADRINDEX1(r)) + + +/* Macros for inserting commands into a secondary dma buffer. + */ + +#define DMALOCALS u8 tempIndex[4]; u32 *dma_ptr; \ + int outcount, num_dwords; + +#define DMAGETPTR(buf) do { \ + dma_ptr = (u32 *)((u8 *)buf->address + buf->used); \ + outcount = 0; \ + num_dwords = buf->used / 4; \ +} while(0) + +#define DMAADVANCE(buf) do { \ + buf->used = num_dwords * 4; \ +} while(0) + +#define DMAOUTREG(reg, val) do { \ + tempIndex[outcount]=ADRINDEX(reg); \ + dma_ptr[++outcount] = val; \ + if (outcount == 4) { \ + outcount = 0; \ + dma_ptr[0] = *(u32 *)tempIndex; \ + dma_ptr+=5; \ + num_dwords += 5; \ + } \ +}while (0) + +/* Not used for emitting state, as we assume the state will always fit + * in a single buffer. + * + * For clip/swap -- choose a maximum number of cliprects so that a single + * buffer is always sufficient? + * + * For vertex cliprects -- ??? + */ +#define CHECK_OVERFLOW(length) do { \ + if (buf->total - buf->used < length * 4) \ + mga_prim_overflow(dev); \ +}while(0) + + +#endif diff --git a/linux/mga_drm_public.h b/linux/mga_drm_public.h index 8c066dd6..20c033c3 100644 --- a/linux/mga_drm_public.h +++ b/linux/mga_drm_public.h @@ -23,7 +23,8 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * Author: Jeff Hartmann <jhartmann@precisioninsight.com> + * Authors: Jeff Hartmann <jhartmann@precisioninsight.com> + * Keith Whitwell <keithw@precisioninsight.com> * * $XFree86$ */ @@ -31,34 +32,38 @@ #ifndef _MGA_DRM_PUBLIC_H_ #define _MGA_DRM_PUBLIC_H_ -/* These defines must match the Xserver code */ +#define MGA_A 0x1 /* alpha */ +#define MGA_F 0x2 /* fog */ +#define MGA_S 0x4 /* specular */ +#define MGA_T2 0x8 /* multitexture */ + #define MGA_WARP_TGZ 0 -#define MGA_WARP_TGZA 1 -#define MGA_WARP_TGZAF 2 -#define MGA_WARP_TGZF 3 -#define MGA_WARP_TGZS 4 -#define MGA_WARP_TGZSA 5 -#define MGA_WARP_TGZSAF 6 -#define MGA_WARP_TGZSF 7 -#define MGA_WARP_T2GZ 8 -#define MGA_WARP_T2GZA 9 -#define MGA_WARP_T2GZAF 10 -#define MGA_WARP_T2GZF 11 -#define MGA_WARP_T2GZS 12 -#define MGA_WARP_T2GZSA 13 -#define MGA_WARP_T2GZSAF 14 -#define MGA_WARP_T2GZSF 15 - -#define MGA_MAX_WARP_PIPES 16 +#define MGA_WARP_TGZA (MGA_A) +#define MGA_WARP_TGZF (MGA_F) +#define MGA_WARP_TGZFA (MGA_F|MGA_A) +#define MGA_WARP_TGZS (MGA_S) +#define MGA_WARP_TGZSA (MGA_S|MGA_A) +#define MGA_WARP_TGZSF (MGA_S|MGA_F) +#define MGA_WARP_TGZSFA (MGA_S|MGA_F|MGA_A) +#define MGA_WARP_T2GZ (MGA_T2) +#define MGA_WARP_T2GZA (MGA_T2|MGA_A) +#define MGA_WARP_T2GZF (MGA_T2|MGA_F) +#define MGA_WARP_T2GZFA (MGA_T2|MGA_A|MGA_F) +#define MGA_WARP_T2GZS (MGA_T2|MGA_S) +#define MGA_WARP_T2GZSA (MGA_T2|MGA_S|MGA_A) +#define MGA_WARP_T2GZSF (MGA_T2|MGA_S|MGA_F) +#define MGA_WARP_T2GZSFA (MGA_T2|MGA_S|MGA_F|MGA_A) + + +#define MGA_MAX_G400_PIPES 16 +#define MGA_MAX_G200_PIPES 8 /* no multitex */ + + +#define MGA_MAX_WARP_PIPES MGA_MAX_G400_PIPES #define MGA_CARD_TYPE_G200 1 #define MGA_CARD_TYPE_G400 2 -/* Bogus values */ - -#define MGA_X_SETUP_SIZE 16 -#define MGA_SETUP_SIZE 16 -#define MGA_TEX_SETUP_SIZE 16 typedef struct _drm_mga_warp_index { int installed; @@ -76,8 +81,7 @@ typedef struct drm_mga_init { int buffer_map_idx; int sarea_priv_offset; int primary_size; - int warp_mc_size; - int type; + int warp_ucode_size; int fbOffset; int backOffset; int depthOffset; @@ -86,9 +90,13 @@ typedef struct drm_mga_init { int cpp; int stride; int sgram; + int chipset; mgaWarpIndex WarpIndex[MGA_MAX_WARP_PIPES]; } drm_mga_init_t; + + + typedef struct _xf86drmClipRectRec { unsigned short x1; unsigned short y1; @@ -96,65 +104,118 @@ typedef struct _xf86drmClipRectRec { unsigned short y2; } xf86drmClipRectRec; -#define _MGA_2D_DIRTY 0 -/* These aren't finals, its just what the Xserver uses */ -#define _MGA_SETUP_PITCH 0 -#define _MGA_SETUP_CXBNDRY 1 -#define _MGA_SETUP_YTOP 2 -#define _MGA_SETUP_YBOT 3 -#define _MGA_SETUP_DSTORG 4 -#define _MGA_SETUP_MACCESS 5 -#define _MGA_SETUP_PLNWT 6 -#define _MGA_SETUP_ZORG 7 -#define _MGA_SETUP_YDSTLEN 8 -#define _MGA_SETUP_YDSTORG 9 -#define _MGA_SETUP_FXBNDRY 10 -#define _MGA_SETUP_SRCORG 11 -#define _MGA_SETUP_DSTORG 12 -#define _MGA_SETUP_SGN 13 -#define _MGA_SETUP_AR0 14 -#define _MGA_SETUP_AR1 15 -#define _MGA_SETUP_AR2 16 -#define _MGA_SETUP_AR3 17 -#define _MGA_SETUP_AR4 18 -#define _MGA_SETUP_AR5 19 -#define _MGA_SETUP_AR6 20 -#define _MGA_SETUP_CXRIGHT 21 -#define _MGA_SETUP_DWGCTL 22 -#define _MGA_SETUP_XYEND 23 -#define _MGA_SETUP_XYSTRT 24 -#define _MGA_SETUP_FCOL 25 -#define _MGA_SETUP_BCOL 26 -#define _MGA_SETUP_PAT0 27 -#define _MGA_SETUP_PAT1 28 -#define _MGA_SETUP_SHIFT 29 -#define _MGA_SETUP_SRC0 30 -#define _MGA_SETUP_SRC1 31 -#define _MGA_SETUP_SRC2 32 -#define _MGA_SETUP_SRC3 33 -#define _MGA_SETUP_OPMODE 34 -#define _MGA_SETUP_WIADDR2 35 -#define _MGA_SETUP_WGETMSB 36 -#define _MGA_SETUP_WVRTXSZ 37 -#define _MGA_SETUP_WACCEPTSEQ 38 -#define _MGA_SETUP_WIADDR 39 -#define _MGA_SETUP_WMISC 40 +#define MGA_CLEAR_FRONTBUFFER 0x1 +#define MGA_CLEAR_BACKBUFFER 0x2 +#define MGA_CLEAR_DEPTHBUFFER 0x4 + +typedef struct drm_mga_clear { + int clear_color; + int clear_depth; + int flags; +} drm_mga_clear_t; + +typedef struct drm_mga_swap { + int flags; /* not actually used? */ +} drm_mga_swap_t; + + + +/* These were context regs, but are constant under the DRI: + */ +#define MGA_CONST_PITCH 0 /* constant */ +#define MGA_CONST_ZORG 7 /* constant */ + +/* Each context has a state: + */ +#define MGA_CTXREG_DSTORG 0 /* top of either front or backbuffer */ +#define MGA_CTXREG_MACCESS 1 /* constant -- except for fog enable */ +#define MGA_CTXREG_PLNWT 2 /* */ +#define MGA_CTXREG_DWGCTL 3 +#define MGA_CTXREG_ALPHACTRL 4 +#define MGA_CTXREG_FOGCOLOR 5 +#define MGA_CTXREG_WFLAG 6 +#define MGA_CTXREG_TDUAL0 7 +#define MGA_CTXREG_TDUAL1 8 +#define MGA_CTX_SETUP_SIZE 9 + +/* Clipper registers - these #defines aren't used. + */ +#define MGA_CLIPREG_CXBNDRY 0 +#define MGA_CLIPREG_YTOP 1 +#define MGA_CLIPREG_YBOT 2 + +/* Do we restore the server state ourselves, or let the X server do + * it after contention? The contended case seems hard to find + * in WakeupHandler. + * + * We need to at least *know* the X server state in order to emit + * swapbuffers and clear-front-buffer requests. + * + * This state is *constant*: + */ +#define MGA_2DREG_YDSTORG 0 +#define MGA_2DREG_MACCESS 1 +#define MGA_2DREG_PITCH 2 +#define MGA_2DREG_DSTORG 3 +#define MGA_2DREG_DWGCTL 4 +#define MGA_2DREG_CXBNDRY 5 +#define MGA_2DREG_YTOP 6 +#define MGA_2DREG_YBOT 7 +#define MGA_2DREG_PLNWT 8 /* write mask -- must be restored */ +#define MGA_2D_SETUP_SIZE 9 + + +/* Each texture unit has a state: + */ +#define MGA_TEXREG_CTL 0 +#define MGA_TEXREG_CTL2 1 +#define MGA_TEXREG_FILTER 2 +#define MGA_TEXREG_BORDERCOL 3 +#define MGA_TEXREG_ORG 4 /* insecure -- validate? */ +#define MGA_TEXREG_ORG1 5 +#define MGA_TEXREG_ORG2 6 +#define MGA_TEXREG_ORG3 7 +#define MGA_TEXREG_ORG4 8 +#define MGA_TEXREG_WIDTH 9 +#define MGA_TEXREG_HEIGHT 10 +#define MGA_TEX_SETUP_SIZE 11 + + +/* Keep this small for testing + */ +#define MGA_NR_SAREA_CLIPRECTS 2 + + +/* Not useful? + */ +#define MGASAREA_NEW_CONTEXT 0x1 +#define MGASAREA_NEW_TEX0 0x2 +#define MGASAREA_NEW_TEX1 0x4 +#define MGASAREA_NEW_PIPE 0x8 +#define MGASAREA_NEW_2D_CONTEXT 0x10 /* does it ever happen? */ typedef struct _drm_mga_sarea { - int CtxOwner; + unsigned int ServerState[MGA_2D_SETUP_SIZE]; + unsigned int ContextState[MGA_CTX_SETUP_SIZE]; + unsigned int Tex0State[MGA_TEX_SETUP_SIZE]; + unsigned int Tex1State[MGA_TEX_SETUP_SIZE]; + unsigned int WarpPipe; + unsigned int dirty; + + unsigned int nbox; + xf86drmClipRectRec boxes[MGA_NR_SAREA_CLIPRECTS]; + + int CtxOwner; /* kernel doesn't touch from here down */ int TexOwner; - unsigned long ServerState[MGA_X_SETUP_SIZE]; - unsigned long ContextState[MGA_SETUP_SIZE]; - unsigned long Tex0State[MGA_TEX_SETUP_SIZE]; - unsigned long Tex1State[MGA_TEX_SETUP_SIZE]; - int WarpPipe; - unsigned long NewState; - int nbox; - xf86drmClipRectRec boxes[256]; } drm_mga_sarea_t; + + + #define DRM_IOCTL_MGA_INIT DRM_IOW( 0x40, drm_mga_init_t) +#define DRM_IOCTL_MGA_SWAP DRM_IOW( 0x40, drm_mga_swap_t) +#define DRM_IOCTL_MGA_CLEAR DRM_IOW( 0x40, drm_mga_clear_t) #endif diff --git a/linux/mga_drv.c b/linux/mga_drv.c index 81c08e81..60cf9b1d 100644 --- a/linux/mga_drv.c +++ b/linux/mga_drv.c @@ -259,7 +259,7 @@ static int mga_takedown(drm_device_t *dev) drm_agp_mem_t *nexte; /* Remove AGP resources, but leave dev->agp - intact until r128_cleanup is called. */ + intact until cleanup is called. */ for (entry = dev->agp->memory; entry; entry = nexte) { nexte = entry->next; if (entry->bound) drm_unbind_agp(entry->memory); diff --git a/linux/mga_drv.h b/linux/mga_drv.h index 5cf61883..0491ed92 100644 --- a/linux/mga_drv.h +++ b/linux/mga_drv.h @@ -38,8 +38,8 @@ typedef struct _drm_mga_private { int buffer_map_idx; drm_mga_sarea_t *sarea_priv; int primary_size; - int warp_mc_size; - int type; + int warp_ucode_size; + int chipset; int fbOffset; int backOffset; int depthOffset; @@ -48,7 +48,8 @@ typedef struct _drm_mga_private { int cpp; int stride; int sgram; - mgaWarpIndex WarpIndex[MGA_MAX_WARP_PIPES]; + int use_agp; + mgaWarpIndex WarpIndex[MGA_MAX_G400_PIPES]; __volatile__ unsigned long softrap_age; atomic_t dispatch_lock; void *ioremap; @@ -57,6 +58,15 @@ typedef struct _drm_mga_private { u32 prim_phys_head; int prim_num_dwords; int prim_max_dwords; + + + /* Some validated register values: + */ + u32 frontOrg; + u32 backOrg; + u32 depthOrg; + u32 mAccess; + } drm_mga_private_t; /* mga_drv.c */ @@ -197,6 +207,7 @@ extern int mga_addmap(struct inode *inode, struct file *filp, #define MGAREG_STATUS 0x1e14 #define MGAREG_STENCIL 0x2cc8 #define MGAREG_STENCILCTL 0x2ccc +#define MGAREG_TDUALSTAGE0 0x2cf8 #define MGAREG_TDUALSTAGE1 0x2cfc #define MGAREG_TEST0 0x1e48 #define MGAREG_TEXBORDERCOL 0x2c5c diff --git a/linux/mga_state.c b/linux/mga_state.c index 1a1ed4fc..f52f054c 100644 --- a/linux/mga_state.c +++ b/linux/mga_state.c @@ -34,176 +34,348 @@ #include "drmP.h" #include "mga_drv.h" #include "mgareg_flags.h" +#include "mga_dma.h" +#include "drm.h" -void mga2drefresh(drm_device_t *dev) +#if 0 +/* How does this work??? + */ +int mgaEmitClipRect(drm_device_t *dev, xf86drmClipRectRec *box) +{ + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->ContextState; + + /* The G400 seems to have an issue with the second WARP not + * stalling clipper register writes. This bothers me, but the only + * way I could get it to never clip the last triangle under any + * circumstances is by inserting TWO dwgsync commands. + */ + if (dev_priv->chipset == MGA_CARD_TYPE_G400) { + DMAOUTREG( MGAREG_DWGSYNC, 0 ); + DMAOUTREG( MGAREG_DWGSYNC, 0 ); + } + + DMAOUTREG( MGAREG_CXBNDRY, ((box->x2)<<16)|(box->x1) ); + DMAOUTREG( MGAREG_YTOP, box->y1 * dev_priv->pitch ); + DMAOUTREG( MGAREG_YBOT, box->y2 * dev_priv->pitch ); + DMAADVANCE(); + return 0; +} +#endif + + +static int mgaEmitContext(drm_device_t *dev, drm_buf_t *buf) { - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->ContextState; + DMALOCALS; + + /* Disallow all write destinations except the front and backbuffer. + */ + if (regs[MGA_CTXREG_DSTORG] != dev_priv->frontOrg && + regs[MGA_CTXREG_DSTORG] != dev_priv->backOrg) + return -1; + + DMAGETPTR( buf ); + DMAOUTREG( MGAREG_DSTORG, regs[MGA_CTXREG_DSTORG] ); + DMAOUTREG( MGAREG_MACCESS, regs[MGA_CTXREG_MACCESS] ); + DMAOUTREG( MGAREG_PLNWT, regs[MGA_CTXREG_PLNWT] ); + DMAOUTREG( MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL] ); + DMAOUTREG( MGAREG_ALPHACTRL, regs[MGA_CTXREG_ALPHACTRL] ); + DMAOUTREG( MGAREG_FOGCOL, regs[MGA_CTXREG_FOGCOLOR] ); + DMAOUTREG( MGAREG_WFLAG, regs[MGA_CTXREG_WFLAG] ); + + if (dev_priv->chipset == MGA_CARD_TYPE_G400) { + DMAOUTREG( MGAREG_WFLAG1, regs[MGA_CTXREG_WFLAG] ); + DMAOUTREG( MGAREG_TDUALSTAGE0, regs[MGA_CTXREG_TDUAL0] ); + DMAOUTREG( MGAREG_TDUALSTAGE1, regs[MGA_CTXREG_TDUAL1] ); + } + DMAADVANCE( buf ); + return 0; } -void mgaContextRefresh(drm_device_t *dev) +/* The texture state routines are quite similar, but are a real mess + * when integrated into a single function. + */ +static int mgaG200EmitTex(drm_device_t *dev, drm_buf_t *buf) { - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->Tex0State; + + DMALOCALS; + + /* Disallow texture reads from PCI space. + */ + if ((regs[MGA_TEXREG_ORG] & 0x3) == 0x1) + return -1; + + DMAGETPTR( buf ); + DMAOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] ); + DMAOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL] ); + DMAOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER] ); + DMAOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL] ); + DMAOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG] ); + DMAOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1] ); + DMAOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2] ); + DMAOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3] ); + DMAOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4] ); + DMAOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH] ); + DMAOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT] ); + DMAOUTREG(0x2d00 + 24*4, regs[MGA_TEXREG_WIDTH] ); + DMAOUTREG(0x2d00 + 34*4, regs[MGA_TEXREG_HEIGHT] ); + + DMAADVANCE( buf ); + + return 0; } -void mgaTex0Refresh(drm_device_t *dev) +static int mgaG400EmitTex0( drm_device_t *dev, drm_buf_t *buf ) { - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->Tex0State; + int multitex = sarea_priv->WarpPipe & MGA_T2; + + DMALOCALS; + DMAGETPTR( buf ); + + /* Disallow texture reads from PCI space. + */ + if ((regs[MGA_TEXREG_ORG] & 0x3) == 0x1) + return -1; + + DMAOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] ); + DMAOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL] ); + DMAOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER] ); + DMAOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL] ); + DMAOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG] ); + DMAOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1] ); + DMAOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2] ); + DMAOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3] ); + DMAOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4] ); + DMAOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH] ); + DMAOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT] ); + DMAOUTREG(0x2d00 + 49*4, 0); + DMAOUTREG(0x2d00 + 57*4, 0); + DMAOUTREG(0x2d00 + 53*4, 0); + DMAOUTREG(0x2d00 + 61*4, 0); + + if (!multitex) { + DMAOUTREG(0x2d00 + 52*4, 0x40 ); + DMAOUTREG(0x2d00 + 60*4, 0x40 ); + } + + DMAOUTREG(0x2d00 + 54*4, regs[MGA_TEXREG_WIDTH] | 0x40 ); + DMAOUTREG(0x2d00 + 62*4, regs[MGA_TEXREG_HEIGHT] | 0x40 ); + + DMAADVANCE( buf ); + return 0; } -void mgaTex1Refresh(drm_device_t *dev) +#define TMC_map1_enable 0x80000000 + + +static int mgaG400EmitTex1( drm_device_t *dev, drm_buf_t *buf ) { - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int *regs = sarea_priv->Tex1State; + + DMALOCALS; + DMAGETPTR(buf); + + /* Disallow texture reads from PCI space. + */ + if ((regs[MGA_TEXREG_ORG] & 0x3) == 0x1) + return -1; + + DMAOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] | TMC_map1_enable); + DMAOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL] ); + DMAOUTREG(MGAREG_TEXFILTER, regs[MGA_TEXREG_FILTER] ); + DMAOUTREG(MGAREG_TEXBORDERCOL, regs[MGA_TEXREG_BORDERCOL] ); + DMAOUTREG(MGAREG_TEXORG, regs[MGA_TEXREG_ORG] ); + DMAOUTREG(MGAREG_TEXORG1, regs[MGA_TEXREG_ORG1] ); + DMAOUTREG(MGAREG_TEXORG2, regs[MGA_TEXREG_ORG2] ); + DMAOUTREG(MGAREG_TEXORG3, regs[MGA_TEXREG_ORG3] ); + DMAOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4] ); + DMAOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH] ); + DMAOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT] ); + DMAOUTREG(0x2d00 + 49*4, 0); + DMAOUTREG(0x2d00 + 57*4, 0); + DMAOUTREG(0x2d00 + 53*4, 0); + DMAOUTREG(0x2d00 + 61*4, 0); + + DMAOUTREG(0x2d00 + 52*4, regs[MGA_TEXREG_WIDTH] | 0x40 ); + DMAOUTREG(0x2d00 + 60*4, regs[MGA_TEXREG_HEIGHT] | 0x40 ); + + DMAOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] ); + + DMAADVANCE( buf ); + return 0; } + + /* WIADDR might not work in sec bufs, might need to use * the primary buffer */ -int mgaG400SwitchPipe(drm_device_t *dev, void *code) +static int mgaG400EmitPipe(drm_device_t *dev, drm_buf_t *buf) { - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - drm_device_dma_t *dma = dev->dma; - drm_dma_t d; - drm_buf_t *buf; - float fParam = 12800.0f; - DMALOCALS(); - - buf = drm_freelist_get(&dma->bufs[order].freelist,_DRM_DMA_WAIT); + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int pipe = sarea_priv->WarpPipe; + float fParam = 12800.0f; + DMALOCALS; - /* This needs to get a buffer to fill */ - - DMAGETPTR(buf); - DMAOUTREG(MGAREG_WIADDR2, WIA_wmode_suspend); + + if (pipe > MGA_MAX_G400_PIPES) + return -1; + + DMAGETPTR(buf); + DMAOUTREG(MGAREG_WIADDR2, WIA_wmode_suspend); - if (sarea_priv->WarpPipe >= 8) { - DMAOUTREG(MGAREG_WVRTXSZ, 0x00001e09); - DMAOUTREG(MGAREG_WACCEPTSEQ, 0x1e000000); - } else { - DMAOUTREG(MGAREG_WVRTXSZ, 0x00001807); - DMAOUTREG(MGAREG_WACCEPTSEQ, 0x18000000); - } + /* Establish vertex size. + */ + if (pipe & MGA_T2) { + DMAOUTREG(MGAREG_WVRTXSZ, 0x00001e09); + DMAOUTREG(MGAREG_WACCEPTSEQ, 0x1e000000); + } else { + DMAOUTREG(MGAREG_WVRTXSZ, 0x00001807); + DMAOUTREG(MGAREG_WACCEPTSEQ, 0x18000000); + } - DMAOUTREG(MGAREG_WFLAG, 0); - DMAOUTREG(MGAREG_WFLAG1, 0); + DMAOUTREG(MGAREG_WFLAG, 0); + DMAOUTREG(MGAREG_WFLAG1, 0); - DMAOUTREG(0x2d00 + 56*4, *((mgaUI32 *)(&fParam))); - DMAOUTREG(MGAREG_DMAPAD, 0); - DMAOUTREG(MGAREG_DMAPAD, 0); + DMAOUTREG(0x2d00 + 56*4, *((u32 *)(&fParam))); + DMAOUTREG(MGAREG_DMAPAD, 0); + DMAOUTREG(MGAREG_DMAPAD, 0); - /* Perhaps only the registers for the Tex Stage 1 should - * be set on the microcode that does multitex, however it - * makes no difference :( - */ - DMAOUTREG(0x2d00 + 49*4, 0); /* Tex stage 0 */ - DMAOUTREG(0x2d00 + 57*4, 0); /* Tex stage 0 */ - DMAOUTREG(0x2d00 + 53*4, 0); /* Tex stage 1 */ - DMAOUTREG(0x2d00 + 61*4, 0); /* Tex stage 1 */ + DMAOUTREG(0x2d00 + 49*4, 0); /* Tex stage 0 */ + DMAOUTREG(0x2d00 + 57*4, 0); /* Tex stage 0 */ + DMAOUTREG(0x2d00 + 53*4, 0); /* Tex stage 1 */ + DMAOUTREG(0x2d00 + 61*4, 0); /* Tex stage 1 */ - DMAOUTREG(0x2d00 + 54*4, 0x40); /* Tex stage 0 : w */ - DMAOUTREG(0x2d00 + 62*4, 0x40); /* Tex stage 0 : h */ - DMAOUTREG(0x2d00 + 52*4, 0x40); /* Tex stage 1 : w */ - DMAOUTREG(0x2d00 + 60*4, 0x40); /* Tex stage 1 : h */ + DMAOUTREG(0x2d00 + 54*4, 0x40); /* Tex stage 0 : w */ + DMAOUTREG(0x2d00 + 62*4, 0x40); /* Tex stage 0 : h */ + DMAOUTREG(0x2d00 + 52*4, 0x40); /* Tex stage 1 : w */ + DMAOUTREG(0x2d00 + 60*4, 0x40); /* Tex stage 1 : h */ - /* Attention! dma pading required due to hw bug (see specs) */ - DMAOUTREG(MGAREG_DMAPAD, 0xffffffff); - DMAOUTREG(MGAREG_DMAPAD, 0xffffffff); - DMAOUTREG(MGAREG_DMAPAD, 0xffffffff); - DMAOUTREG(MGAREG_WIADDR2,(unsigned long)(code) | WIA_wmode_start | - WIA_wagp_agp); - DMAADVANCE(buf); - d.context = DRM_KERNEL_CONTEXT; - d.send_count = 1; - d.send_indices = &buf->idx; - d.send_sizes = &buf->used; - d.flags = _DRM_DMA_GENERAL; - d.request_count = 0; - d.request_size = 0; - d.request_indices = NULL; - d.request_sizes = NULL; - d.granted_count = 0; - drm_dma_enqueue(dev, &d); - return 0; + /* Dma pading required due to hw bug */ + DMAOUTREG(MGAREG_DMAPAD, 0xffffffff); + DMAOUTREG(MGAREG_DMAPAD, 0xffffffff); + DMAOUTREG(MGAREG_DMAPAD, 0xffffffff); + DMAOUTREG(MGAREG_WIADDR2, (dev_priv->WarpIndex[pipe].phys_addr | + WIA_wmode_start | WIA_wagp_agp)); + DMAADVANCE(buf); + return 0; } -int mgaG200SwitchPipe(drm_device_t *dev, void *code) +static int mgaG200EmitPipe( drm_device_t *dev, drm_buf_t *buf ) { - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_device_dma_t *dma = dev->dma; - drm_dma_t d; - drm_buf_t *buf; - DMALOCALS; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int pipe = sarea_priv->WarpPipe; + DMALOCALS; - /* This needs to get a buffer to fill */ - buf = drm_freelist_get(&dma->bufs[order].freelist,_DRM_DMA_WAIT); - - DMAGETPTR(buf); - DMAOUTREG(MGAREG_WIADDR, WIA_wmode_suspend); - DMAOUTREG(MGAREG_WVRTXSZ, 7); - DMAOUTREG(MGAREG_WFLAG, 0); - DMAOUTREG(0x2d00 + 24*4, 0); // tex w/h + if (pipe > MGA_MAX_G200_PIPES) + return -1; + + DMAGETPTR(buf); + DMAOUTREG(MGAREG_WIADDR, WIA_wmode_suspend); + DMAOUTREG(MGAREG_WVRTXSZ, 7); + DMAOUTREG(MGAREG_WFLAG, 0); + DMAOUTREG(0x2d00 + 24*4, 0); /* tex w/h */ - DMAOUTREG(0x2d00 + 25*4, 0x100); - DMAOUTREG(0x2d00 + 34*4, 0); // tex w/h - DMAOUTREG(0x2d00 + 42*4, 0xFFFF); - DMAOUTREG(0x2d00 + 60*4, 0xFFFF); + DMAOUTREG(0x2d00 + 25*4, 0x100); + DMAOUTREG(0x2d00 + 34*4, 0); /* tex w/h */ + DMAOUTREG(0x2d00 + 42*4, 0xFFFF); + DMAOUTREG(0x2d00 + 60*4, 0xFFFF); - /* Attention! dma pading required due to hw bug (see specs) */ - DMAOUTREG(MGAREG_DMAPAD, 0xffffffff); - DMAOUTREG(MGAREG_DMAPAD, 0xffffffff); - DMAOUTREG(MGAREG_DMAPAD, 0xffffffff); - DMAOUTREG(MGAREG_WIADDR,(unsigned long)(code) | WIA_wmode_start | - WIA_wagp_agp); - DMAADVANCE(buf); - d.context = DRM_KERNEL_CONTEXT; - d.send_count = 1; - d.send_indices = &buf->idx; - d.send_sizes = &buf->used; - d.flags = _DRM_DMA_GENERAL; - d.request_count = 0; - d.request_size = 0; - d.request_indices = NULL; - d.request_sizes = NULL; - d.granted_count = 0; - drm_dma_enqueue(dev, &d); - return 0; + /* Dma pading required due to hw bug */ + DMAOUTREG(MGAREG_DMAPAD, 0xffffffff); + DMAOUTREG(MGAREG_DMAPAD, 0xffffffff); + DMAOUTREG(MGAREG_DMAPAD, 0xffffffff); + DMAOUTREG(MGAREG_WIADDR, (dev_priv->WarpIndex[pipe].phys_addr | + WIA_wmode_start | WIA_wagp_agp)); + + DMAADVANCE(buf); + return 0; } -void mgaWarpPipeRefresh(drm_device_t *dev) + + +void mgaEmitState( drm_device_t *dev ) { - drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - void *code; - int failure; - - code = (void *)dev_priv->WarpIndex[sarea_priv->WarpPipe].phys_addr; - - if(!code) { - printk("Invalid warp code selected : %d\n", sarea_priv->WarpPipe); - code = (void *)dev_priv->WarpIndex[0].phys_addr; - - if(!code) { - DRM_ERROR("No Warp Pipes Loaded\n"); - return; - } - } - switch(dev_priv->type) { - case MGA_CARD_TYPE_G400: - failure = mgaG400SwitchPipe(dev, code); - break; - case MGA_CARD_TYPE_G200: - failure = mgaG200SwitchPipe(dev, code); - break; - } - if(failure) { - DRM_ERROR("Failed to switch warp pipes to : %d\n", - sarea_priv->WarpPipe); - } + drm_buf_t *buf; + drm_device_dma_t *dma = dev->dma; + drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; + drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int dirty = sarea_priv->dirty ; + int rv = 0; + + int order = 1; /* ???? */ + + /* Put all state onto a single buffer. + */ + buf = drm_freelist_get(&dma->bufs[order].freelist,_DRM_DMA_WAIT); + + + if (dev_priv->chipset == MGA_CARD_TYPE_G400) { + + if (dirty & MGASAREA_NEW_CONTEXT) + rv |= mgaEmitContext( dev, buf ); + + if (dirty & MGASAREA_NEW_TEX1) + rv |= mgaG400EmitTex1( dev, buf ); + + if (dirty & MGASAREA_NEW_TEX0) + rv |= mgaG400EmitTex0( dev, buf ); + + if (dirty & MGASAREA_NEW_PIPE) + rv |= mgaG400EmitPipe( dev, buf ); + + } else { + + if (dirty & MGASAREA_NEW_CONTEXT) + rv |= mgaEmitContext( dev, buf ); + + if (dirty & MGASAREA_NEW_TEX0) + rv |= mgaG200EmitTex( dev, buf ); + + if (dirty & MGASAREA_NEW_PIPE) + rv |= mgaG200EmitPipe( dev, buf ); + } + + + if (rv == 0) { + drm_dma_t d; + + sarea_priv->dirty = 0; + + d.context = DRM_KERNEL_CONTEXT; + d.send_count = 1; + d.send_indices = &buf->idx; + d.send_sizes = &buf->used; + d.flags = _DRM_DMA_GENERAL; + d.request_count = 0; + d.request_size = 0; + d.request_indices = NULL; + d.request_sizes = NULL; + d.granted_count = 0; + drm_dma_enqueue(dev, &d); + } else { + /* Won't render anything till we get a good state from a + * client. + */ + sarea_priv->dirty = ~0; + drm_freelist_put( dev, &dma->bufs[order].freelist, buf ); + } } diff --git a/shared-core/drm.h b/shared-core/drm.h index 01b2024c..01c5bdc8 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -162,9 +162,11 @@ typedef enum drm_dma_flags { /* These values *MUST* match xf86drm.h */ _DRM_DMA_LARGER_OK = 0x40, /* Larger-than-requested buffers ok */ /* Specially for MGA, but not limited to use by it */ + _DRM_DMA_TYPE_MASK = 0x0F000000, + _DRM_DMA_GENERAL = 0x00000000, /* the default type */ _DRM_DMA_VERTEX = 0x01000000, _DRM_DMA_SETUP = 0x02000000, - _DRM_DMA_BLIT = 0x04000000 + _DRM_DMA_BLIT = 0x03000000 } drm_dma_flags_t; typedef struct drm_buf_desc { diff --git a/shared/drm.h b/shared/drm.h index 01b2024c..01c5bdc8 100644 --- a/shared/drm.h +++ b/shared/drm.h @@ -162,9 +162,11 @@ typedef enum drm_dma_flags { /* These values *MUST* match xf86drm.h */ _DRM_DMA_LARGER_OK = 0x40, /* Larger-than-requested buffers ok */ /* Specially for MGA, but not limited to use by it */ + _DRM_DMA_TYPE_MASK = 0x0F000000, + _DRM_DMA_GENERAL = 0x00000000, /* the default type */ _DRM_DMA_VERTEX = 0x01000000, _DRM_DMA_SETUP = 0x02000000, - _DRM_DMA_BLIT = 0x04000000 + _DRM_DMA_BLIT = 0x03000000 } drm_dma_flags_t; typedef struct drm_buf_desc { |