Commit 6795c985 authored by Dave Airlie's avatar Dave Airlie Committed by Dave Airlie

Add support for PCI MGA cards to MGA DRM.

This patch adds serveral new ioctls and a new query to get_param query to
support PCI MGA cards.

Two ioctls were added to implement interrupt based waiting.  With this change,
the client-side driver no longer needs to map the primary DMA region or the
MMIO region.  Previously, end-of-frame waiting was done by busy waiting in the
client-side driver until one of the MMIO registers (the current DMA pointer)
matched a pointer to the end of primary DMA space.  By using interrupts, the
busy waiting and the extra mappings are removed.

A third ioctl was added to bootstrap DMA.  This ioctl, which is used by the
X-server, moves a *LOT* of code from the X-server into the kernel.  This allows
the kernel to do whatever needs to be done to setup DMA buffers.  The entire
process and the locations of the buffers are hidden from user-mode.

Additionally, a get_param query was added to differentiate between G4x0 cards
and G550 cards.  A gap was left in the numbering sequence so that, if needed,
G450 cards could be distinguished from G400 cards.  According to Ville
Syrjälä, the G4x0 cards and the G550 cards handle anisotropic filtering
differently.  This seems the most compatible way to let the client-side driver
know which card it's own.  Doing this very small change now eliminates the
need to bump the DRM minor version twice.

http://marc.theaimsgroup.com/?l=dri-devel&m=106625815319773&w=2

(airlied - this may not work at this point, I think the follow on buffer
 cleanup patches will be needed)

From: Ian Romanick <idr@us.ibm.com>
Signed-off-by: default avatarDave Airlie <airlied@linux.ie>
parent b5d499cf
...@@ -82,7 +82,7 @@ endchoice ...@@ -82,7 +82,7 @@ endchoice
config DRM_MGA config DRM_MGA
tristate "Matrox g200/g400" tristate "Matrox g200/g400"
depends on DRM && AGP depends on DRM
help help
Choose this option if you have a Matrox G200, G400 or G450 graphics Choose this option if you have a Matrox G200, G400 or G450 graphics
card. If M is selected, the module will be called mga. AGP card. If M is selected, the module will be called mga. AGP
......
This diff is collapsed.
...@@ -226,10 +226,6 @@ typedef struct _drm_mga_sarea { ...@@ -226,10 +226,6 @@ typedef struct _drm_mga_sarea {
} drm_mga_sarea_t; } drm_mga_sarea_t;
/* WARNING: If you change any of these defines, make sure to change the
* defines in the Xserver file (xf86drmMga.h)
*/
/* MGA specific ioctls /* MGA specific ioctls
* The device specific ioctl range is 0x40 to 0x79. * The device specific ioctl range is 0x40 to 0x79.
*/ */
...@@ -244,6 +240,14 @@ typedef struct _drm_mga_sarea { ...@@ -244,6 +240,14 @@ typedef struct _drm_mga_sarea {
#define DRM_MGA_BLIT 0x08 #define DRM_MGA_BLIT 0x08
#define DRM_MGA_GETPARAM 0x09 #define DRM_MGA_GETPARAM 0x09
/* 3.2:
* ioctls for operating on fences.
*/
#define DRM_MGA_SET_FENCE 0x0a
#define DRM_MGA_WAIT_FENCE 0x0b
#define DRM_MGA_DMA_BOOTSTRAP 0x0c
#define DRM_IOCTL_MGA_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_INIT, drm_mga_init_t) #define DRM_IOCTL_MGA_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_INIT, drm_mga_init_t)
#define DRM_IOCTL_MGA_FLUSH DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_FLUSH, drm_lock_t) #define DRM_IOCTL_MGA_FLUSH DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_FLUSH, drm_lock_t)
#define DRM_IOCTL_MGA_RESET DRM_IO( DRM_COMMAND_BASE + DRM_MGA_RESET) #define DRM_IOCTL_MGA_RESET DRM_IO( DRM_COMMAND_BASE + DRM_MGA_RESET)
...@@ -254,6 +258,9 @@ typedef struct _drm_mga_sarea { ...@@ -254,6 +258,9 @@ typedef struct _drm_mga_sarea {
#define DRM_IOCTL_MGA_ILOAD DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_ILOAD, drm_mga_iload_t) #define DRM_IOCTL_MGA_ILOAD DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_ILOAD, drm_mga_iload_t)
#define DRM_IOCTL_MGA_BLIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_BLIT, drm_mga_blit_t) #define DRM_IOCTL_MGA_BLIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_BLIT, drm_mga_blit_t)
#define DRM_IOCTL_MGA_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_GETPARAM, drm_mga_getparam_t) #define DRM_IOCTL_MGA_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_GETPARAM, drm_mga_getparam_t)
#define DRM_IOCTL_MGA_SET_FENCE DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_SET_FENCE, uint32_t)
#define DRM_IOCTL_MGA_WAIT_FENCE DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_WAIT_FENCE, uint32_t)
#define DRM_IOCTL_MGA_DMA_BOOTSTRAP DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_DMA_BOOTSTRAP, drm_mga_dma_bootstrap_t)
typedef struct _drm_mga_warp_index { typedef struct _drm_mga_warp_index {
int installed; int installed;
...@@ -292,12 +299,72 @@ typedef struct drm_mga_init { ...@@ -292,12 +299,72 @@ typedef struct drm_mga_init {
unsigned long buffers_offset; unsigned long buffers_offset;
} drm_mga_init_t; } drm_mga_init_t;
typedef struct drm_mga_fullscreen { typedef struct drm_mga_dma_bootstrap {
enum { /**
MGA_INIT_FULLSCREEN = 0x01, * \name AGP texture region
MGA_CLEANUP_FULLSCREEN = 0x02 *
} func; * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, these fields will
} drm_mga_fullscreen_t; * be filled in with the actual AGP texture settings.
*
* \warning
* If these fields are non-zero, but dma_mga_dma_bootstrap::agp_mode
* is zero, it means that PCI memory (most likely through the use of
* an IOMMU) is being used for "AGP" textures.
*/
/*@{*/
drm_handle_t texture_handle; /**< Handle used to map AGP textures. */
uint32_t texture_size; /**< Size of the AGP texture region. */
/*@}*/
/**
* Requested size of the primary DMA region.
*
* On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be
* filled in with the actual AGP mode. If AGP was not available
*/
uint32_t primary_size;
/**
* Requested number of secondary DMA buffers.
*
* On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be
* filled in with the actual number of secondary DMA buffers
* allocated. Particularly when PCI DMA is used, this may be
* (subtantially) less than the number requested.
*/
uint32_t secondary_bin_count;
/**
* Requested size of each secondary DMA buffer.
*
* While the kernel \b is free to reduce
* dma_mga_dma_bootstrap::secondary_bin_count, it is \b not allowed
* to reduce dma_mga_dma_bootstrap::secondary_bin_size.
*/
uint32_t secondary_bin_size;
/**
* Bit-wise mask of AGPSTAT2_* values. Currently only \c AGPSTAT2_1X,
* \c AGPSTAT2_2X, and \c AGPSTAT2_4X are supported. If this value is
* zero, it means that PCI DMA should be used, even if AGP is
* possible.
*
* On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be
* filled in with the actual AGP mode. If AGP was not available
* (i.e., PCI DMA was used), this value will be zero.
*/
uint32_t agp_mode;
/**
* Desired AGP GART size, measured in megabytes.
*/
uint8_t agp_size;
} drm_mga_dma_bootstrap_t;
typedef struct drm_mga_clear { typedef struct drm_mga_clear {
unsigned int flags; unsigned int flags;
...@@ -342,6 +409,14 @@ typedef struct _drm_mga_blit { ...@@ -342,6 +409,14 @@ typedef struct _drm_mga_blit {
*/ */
#define MGA_PARAM_IRQ_NR 1 #define MGA_PARAM_IRQ_NR 1
/* 3.2: Query the actual card type. The DDX only distinguishes between
* G200 chips and non-G200 chips, which it calls G400. It turns out that
* there are some very sublte differences between the G4x0 chips and the G550
* chips. Using this parameter query, a client-side driver can detect the
* difference between a G4x0 and a G550.
*/
#define MGA_PARAM_CARD_TYPE 2
typedef struct drm_mga_getparam { typedef struct drm_mga_getparam {
int param; int param;
void __user *value; void __user *value;
......
...@@ -38,11 +38,11 @@ ...@@ -38,11 +38,11 @@
#define DRIVER_NAME "mga" #define DRIVER_NAME "mga"
#define DRIVER_DESC "Matrox G200/G400" #define DRIVER_DESC "Matrox G200/G400"
#define DRIVER_DATE "20051013" #define DRIVER_DATE "20050607"
#define DRIVER_MAJOR 3 #define DRIVER_MAJOR 3
#define DRIVER_MINOR 1 #define DRIVER_MINOR 2
#define DRIVER_PATCHLEVEL 1 #define DRIVER_PATCHLEVEL 0
typedef struct drm_mga_primary_buffer { typedef struct drm_mga_primary_buffer {
u8 *start; u8 *start;
...@@ -87,9 +87,43 @@ typedef struct drm_mga_private { ...@@ -87,9 +87,43 @@ typedef struct drm_mga_private {
int chipset; int chipset;
int usec_timeout; int usec_timeout;
/**
* If set, the new DMA initialization sequence was used. This is
* primarilly used to select how the driver should uninitialized its
* internal DMA structures.
*/
int used_new_dma_init;
/**
* If AGP memory is used for DMA buffers, this will be the value
* \c MGA_PAGPXFER. Otherwise, it will be zero (for a PCI transfer).
*/
u32 dma_access;
/**
* If AGP memory is used for DMA buffers, this will be the value
* \c MGA_WAGP_ENABLE. Otherwise, it will be zero (for a PCI
* transfer).
*/
u32 wagp_enable;
/**
* \name MMIO region parameters.
*
* \sa drm_mga_private_t::mmio
*/
/*@{*/
u32 mmio_base; /**< Bus address of base of MMIO. */
u32 mmio_size; /**< Size of the MMIO region. */
/*@}*/
u32 clear_cmd; u32 clear_cmd;
u32 maccess; u32 maccess;
wait_queue_head_t fence_queue;
atomic_t last_fence_retired;
u32 next_fence_to_post;
unsigned int fb_cpp; unsigned int fb_cpp;
unsigned int front_offset; unsigned int front_offset;
unsigned int front_pitch; unsigned int front_pitch;
...@@ -108,35 +142,43 @@ typedef struct drm_mga_private { ...@@ -108,35 +142,43 @@ typedef struct drm_mga_private {
drm_local_map_t *status; drm_local_map_t *status;
drm_local_map_t *warp; drm_local_map_t *warp;
drm_local_map_t *primary; drm_local_map_t *primary;
drm_local_map_t *buffers;
drm_local_map_t *agp_textures; drm_local_map_t *agp_textures;
DRM_AGP_MEM *agp_mem;
unsigned int agp_pages;
} drm_mga_private_t; } drm_mga_private_t;
/* mga_dma.c */ /* mga_dma.c */
extern int mga_dma_init( DRM_IOCTL_ARGS ); extern int mga_driver_preinit(drm_device_t * dev, unsigned long flags);
extern int mga_dma_flush( DRM_IOCTL_ARGS ); extern int mga_dma_bootstrap(DRM_IOCTL_ARGS);
extern int mga_dma_reset( DRM_IOCTL_ARGS ); extern int mga_dma_init(DRM_IOCTL_ARGS);
extern int mga_dma_buffers( DRM_IOCTL_ARGS ); extern int mga_dma_flush(DRM_IOCTL_ARGS);
extern void mga_driver_pretakedown(drm_device_t *dev); extern int mga_dma_reset(DRM_IOCTL_ARGS);
extern int mga_driver_dma_quiescent(drm_device_t *dev); extern int mga_dma_buffers(DRM_IOCTL_ARGS);
extern int mga_driver_postcleanup(drm_device_t * dev);
extern int mga_do_wait_for_idle( drm_mga_private_t *dev_priv ); extern void mga_driver_pretakedown(drm_device_t * dev);
extern int mga_driver_dma_quiescent(drm_device_t * dev);
extern void mga_do_dma_flush( drm_mga_private_t *dev_priv );
extern void mga_do_dma_wrap_start( drm_mga_private_t *dev_priv ); extern int mga_do_wait_for_idle(drm_mga_private_t * dev_priv);
extern void mga_do_dma_wrap_end( drm_mga_private_t *dev_priv );
extern void mga_do_dma_flush(drm_mga_private_t * dev_priv);
extern void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv);
extern void mga_do_dma_wrap_end(drm_mga_private_t * dev_priv);
extern int mga_freelist_put( drm_device_t *dev, drm_buf_t *buf ); extern int mga_freelist_put( drm_device_t *dev, drm_buf_t *buf );
/* mga_warp.c */ /* mga_warp.c */
extern int mga_warp_install_microcode( drm_mga_private_t *dev_priv ); extern unsigned int mga_warp_microcode_size(const drm_mga_private_t * dev_priv);
extern int mga_warp_init( drm_mga_private_t *dev_priv ); extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv);
extern int mga_warp_init(drm_mga_private_t * dev_priv);
extern int mga_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence);
extern irqreturn_t mga_driver_irq_handler( DRM_IRQ_ARGS ); /* mga_irq.c */
extern void mga_driver_irq_preinstall( drm_device_t *dev ); extern int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence);
extern void mga_driver_irq_postinstall( drm_device_t *dev ); extern int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence);
extern void mga_driver_irq_uninstall( drm_device_t *dev ); extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
extern void mga_driver_irq_preinstall(drm_device_t * dev);
extern void mga_driver_irq_postinstall(drm_device_t * dev);
extern void mga_driver_irq_uninstall(drm_device_t * dev);
extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg); unsigned long arg);
...@@ -527,6 +569,12 @@ do { \ ...@@ -527,6 +569,12 @@ do { \
*/ */
#define MGA_EXEC 0x0100 #define MGA_EXEC 0x0100
/* AGP PLL encoding (for G200 only).
*/
#define MGA_AGP_PLL 0x1e4c
# define MGA_AGP2XPLL_DISABLE (0 << 0)
# define MGA_AGP2XPLL_ENABLE (1 << 0)
/* Warp registers /* Warp registers
*/ */
#define MGA_WR0 0x2d00 #define MGA_WR0 0x2d00
......
...@@ -41,15 +41,40 @@ irqreturn_t mga_driver_irq_handler( DRM_IRQ_ARGS ) ...@@ -41,15 +41,40 @@ irqreturn_t mga_driver_irq_handler( DRM_IRQ_ARGS )
drm_mga_private_t *dev_priv = drm_mga_private_t *dev_priv =
(drm_mga_private_t *)dev->dev_private; (drm_mga_private_t *)dev->dev_private;
int status; int status;
int handled = 0;
status = MGA_READ(MGA_STATUS);
status = MGA_READ( MGA_STATUS );
/* VBLANK interrupt */ /* VBLANK interrupt */
if ( status & MGA_VLINEPEN ) { if ( status & MGA_VLINEPEN ) {
MGA_WRITE( MGA_ICLEAR, MGA_VLINEICLR ); MGA_WRITE( MGA_ICLEAR, MGA_VLINEICLR );
atomic_inc(&dev->vbl_received); atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue); DRM_WAKEUP(&dev->vbl_queue);
drm_vbl_send_signals( dev ); drm_vbl_send_signals(dev);
handled = 1;
}
/* SOFTRAP interrupt */
if (status & MGA_SOFTRAPEN) {
const u32 prim_start = MGA_READ(MGA_PRIMADDRESS);
const u32 prim_end = MGA_READ(MGA_PRIMEND);
MGA_WRITE(MGA_ICLEAR, MGA_SOFTRAPICLR);
/* In addition to clearing the interrupt-pending bit, we
* have to write to MGA_PRIMEND to re-start the DMA operation.
*/
if ( (prim_start & ~0x03) != (prim_end & ~0x03) ) {
MGA_WRITE(MGA_PRIMEND, prim_end);
}
atomic_inc(&dev_priv->last_fence_retired);
DRM_WAKEUP(&dev_priv->fence_queue);
handled = 1;
}
if ( handled ) {
return IRQ_HANDLED; return IRQ_HANDLED;
} }
return IRQ_NONE; return IRQ_NONE;
...@@ -73,9 +98,28 @@ int mga_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence) ...@@ -73,9 +98,28 @@ int mga_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
return ret; return ret;
} }
void mga_driver_irq_preinstall( drm_device_t *dev ) { int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence)
drm_mga_private_t *dev_priv = {
(drm_mga_private_t *)dev->dev_private; drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
unsigned int cur_fence;
int ret = 0;
/* Assume that the user has missed the current sequence number
* by about a day rather than she wants to wait for years
* using fences.
*/
DRM_WAIT_ON(ret, dev_priv->fence_queue, 3 * DRM_HZ,
(((cur_fence = atomic_read(&dev_priv->last_fence_retired))
- *sequence) <= (1 << 23)));
*sequence = cur_fence;
return ret;
}
void mga_driver_irq_preinstall(drm_device_t * dev)
{
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
/* Disable *all* interrupts */ /* Disable *all* interrupts */
MGA_WRITE( MGA_IEN, 0 ); MGA_WRITE( MGA_IEN, 0 );
...@@ -83,12 +127,14 @@ void mga_driver_irq_preinstall( drm_device_t *dev ) { ...@@ -83,12 +127,14 @@ void mga_driver_irq_preinstall( drm_device_t *dev ) {
MGA_WRITE( MGA_ICLEAR, ~0 ); MGA_WRITE( MGA_ICLEAR, ~0 );
} }
void mga_driver_irq_postinstall( drm_device_t *dev ) { void mga_driver_irq_postinstall(drm_device_t * dev)
drm_mga_private_t *dev_priv = {
(drm_mga_private_t *)dev->dev_private; drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
DRM_INIT_WAITQUEUE( &dev_priv->fence_queue );
/* Turn on VBL interrupt */ /* Turn on vertical blank interrupt and soft trap interrupt. */
MGA_WRITE( MGA_IEN, MGA_VLINEIEN ); MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
} }
void mga_driver_irq_uninstall( drm_device_t *dev ) { void mga_driver_irq_uninstall( drm_device_t *dev ) {
...@@ -98,5 +144,7 @@ void mga_driver_irq_uninstall( drm_device_t *dev ) { ...@@ -98,5 +144,7 @@ void mga_driver_irq_uninstall( drm_device_t *dev ) {
return; return;
/* Disable *all* interrupts */ /* Disable *all* interrupts */
MGA_WRITE( MGA_IEN, 0 ); MGA_WRITE(MGA_IEN, 0);
dev->irq_enabled = 0;
} }
...@@ -53,16 +53,16 @@ static void mga_emit_clip_rect( drm_mga_private_t *dev_priv, ...@@ -53,16 +53,16 @@ static void mga_emit_clip_rect( drm_mga_private_t *dev_priv,
/* Force reset of DWGCTL on G400 (eliminates clip disable bit). /* Force reset of DWGCTL on G400 (eliminates clip disable bit).
*/ */
if ( dev_priv->chipset == MGA_CARD_TYPE_G400 ) { if (dev_priv->chipset == MGA_CARD_TYPE_G400) {
DMA_BLOCK( MGA_DWGCTL, ctx->dwgctl, DMA_BLOCK(MGA_DWGCTL, ctx->dwgctl,
MGA_LEN + MGA_EXEC, 0x80000000, MGA_LEN + MGA_EXEC, 0x80000000,
MGA_DWGCTL, ctx->dwgctl, MGA_DWGCTL, ctx->dwgctl,
MGA_LEN + MGA_EXEC, 0x80000000 ); MGA_LEN + MGA_EXEC, 0x80000000);
} }
DMA_BLOCK( MGA_DMAPAD, 0x00000000, DMA_BLOCK(MGA_DMAPAD, 0x00000000,
MGA_CXBNDRY, (box->x2 << 16) | box->x1, MGA_CXBNDRY, ((box->x2 - 1) << 16) | box->x1,
MGA_YTOP, box->y1 * pitch, MGA_YTOP, box->y1 * pitch,
MGA_YBOT, box->y2 * pitch ); MGA_YBOT, (box->y2 - 1) * pitch);
ADVANCE_DMA(); ADVANCE_DMA();
} }
...@@ -260,12 +260,11 @@ static __inline__ void mga_g200_emit_pipe( drm_mga_private_t *dev_priv ) ...@@ -260,12 +260,11 @@ static __inline__ void mga_g200_emit_pipe( drm_mga_private_t *dev_priv )
/* Padding required to to hardware bug. /* Padding required to to hardware bug.
*/ */
DMA_BLOCK( MGA_DMAPAD, 0xffffffff, DMA_BLOCK(MGA_DMAPAD, 0xffffffff,
MGA_DMAPAD, 0xffffffff, MGA_DMAPAD, 0xffffffff,
MGA_DMAPAD, 0xffffffff, MGA_DMAPAD, 0xffffffff,
MGA_WIADDR, (dev_priv->warp_pipe_phys[pipe] | MGA_WIADDR, (dev_priv->warp_pipe_phys[pipe] |
MGA_WMODE_START | MGA_WMODE_START | dev_priv->wagp_enable));
MGA_WAGP_ENABLE) );
ADVANCE_DMA(); ADVANCE_DMA();
} }
...@@ -342,12 +341,11 @@ static __inline__ void mga_g400_emit_pipe( drm_mga_private_t *dev_priv ) ...@@ -342,12 +341,11 @@ static __inline__ void mga_g400_emit_pipe( drm_mga_private_t *dev_priv )
MGA_WR60, MGA_G400_WR_MAGIC ); /* tex1 height */ MGA_WR60, MGA_G400_WR_MAGIC ); /* tex1 height */
/* Padding required to to hardware bug */ /* Padding required to to hardware bug */
DMA_BLOCK( MGA_DMAPAD, 0xffffffff, DMA_BLOCK(MGA_DMAPAD, 0xffffffff,
MGA_DMAPAD, 0xffffffff, MGA_DMAPAD, 0xffffffff,
MGA_DMAPAD, 0xffffffff, MGA_DMAPAD, 0xffffffff,
MGA_WIADDR2, (dev_priv->warp_pipe_phys[pipe] | MGA_WIADDR2, (dev_priv->warp_pipe_phys[pipe] |
MGA_WMODE_START | MGA_WMODE_START | dev_priv->wagp_enable));
MGA_WAGP_ENABLE) );
ADVANCE_DMA(); ADVANCE_DMA();
} }
...@@ -459,9 +457,9 @@ static int mga_verify_state( drm_mga_private_t *dev_priv ) ...@@ -459,9 +457,9 @@ static int mga_verify_state( drm_mga_private_t *dev_priv )
if ( dirty & MGA_UPLOAD_TEX0 ) if ( dirty & MGA_UPLOAD_TEX0 )
ret |= mga_verify_tex( dev_priv, 0 ); ret |= mga_verify_tex( dev_priv, 0 );
if ( dev_priv->chipset == MGA_CARD_TYPE_G400 ) { if (dev_priv->chipset >= MGA_CARD_TYPE_G400) {
if ( dirty & MGA_UPLOAD_TEX1 ) if (dirty & MGA_UPLOAD_TEX1)
ret |= mga_verify_tex( dev_priv, 1 ); ret |= mga_verify_tex(dev_priv, 1);
if ( dirty & MGA_UPLOAD_PIPE ) if ( dirty & MGA_UPLOAD_PIPE )
ret |= ( sarea_priv->warp_pipe > MGA_MAX_G400_PIPES ); ret |= ( sarea_priv->warp_pipe > MGA_MAX_G400_PIPES );
...@@ -686,12 +684,12 @@ static void mga_dma_dispatch_vertex( drm_device_t *dev, drm_buf_t *buf ) ...@@ -686,12 +684,12 @@ static void mga_dma_dispatch_vertex( drm_device_t *dev, drm_buf_t *buf )
BEGIN_DMA( 1 ); BEGIN_DMA( 1 );
DMA_BLOCK( MGA_DMAPAD, 0x00000000, DMA_BLOCK(MGA_DMAPAD, 0x00000000,
MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000,
MGA_SECADDRESS, (address | MGA_SECADDRESS, (address |
MGA_DMA_VERTEX), MGA_DMA_VERTEX),
MGA_SECEND, ((address + length) | MGA_SECEND, ((address + length) |
MGA_PAGPXFER) ); dev_priv->dma_access));
ADVANCE_DMA(); ADVANCE_DMA();
} while ( ++i < sarea_priv->nbox ); } while ( ++i < sarea_priv->nbox );
...@@ -733,11 +731,11 @@ static void mga_dma_dispatch_indices( drm_device_t *dev, drm_buf_t *buf, ...@@ -733,11 +731,11 @@ static void mga_dma_dispatch_indices( drm_device_t *dev, drm_buf_t *buf,
BEGIN_DMA( 1 ); BEGIN_DMA( 1 );
DMA_BLOCK( MGA_DMAPAD, 0x00000000, DMA_BLOCK(MGA_DMAPAD, 0x00000000,
MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000,
MGA_SETUPADDRESS, address + start, MGA_SETUPADDRESS, address + start,
MGA_SETUPEND, ((address + end) | MGA_SETUPEND, ((address + end) |
MGA_PAGPXFER) ); dev_priv->dma_access));
ADVANCE_DMA(); ADVANCE_DMA();
} while ( ++i < sarea_priv->nbox ); } while ( ++i < sarea_priv->nbox );
...@@ -764,7 +762,7 @@ static void mga_dma_dispatch_iload( drm_device_t *dev, drm_buf_t *buf, ...@@ -764,7 +762,7 @@ static void mga_dma_dispatch_iload( drm_device_t *dev, drm_buf_t *buf,
drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_buf_priv_t *buf_priv = buf->dev_private; drm_mga_buf_priv_t *buf_priv = buf->dev_private;
drm_mga_context_regs_t *ctx = &dev_priv->sarea_priv->context_state; drm_mga_context_regs_t *ctx = &dev_priv->sarea_priv->context_state;
u32 srcorg = buf->bus_address | MGA_SRCACC_AGP | MGA_SRCMAP_SYSMEM; u32 srcorg = buf->bus_address | dev_priv->dma_access | MGA_SRCMAP_SYSMEM;
u32 y2; u32 y2;
DMA_LOCALS; DMA_LOCALS;
DRM_DEBUG( "buf=%d used=%d\n", buf->idx, buf->used ); DRM_DEBUG( "buf=%d used=%d\n", buf->idx, buf->used );
...@@ -1095,6 +1093,9 @@ static int mga_getparam( DRM_IOCTL_ARGS ) ...@@ -1095,6 +1093,9 @@ static int mga_getparam( DRM_IOCTL_ARGS )
case MGA_PARAM_IRQ_NR: case MGA_PARAM_IRQ_NR:
value = dev->irq; value = dev->irq;
break; break;
case MGA_PARAM_CARD_TYPE:
value = dev_priv->chipset;
break;
default: default:
return DRM_ERR(EINVAL); return DRM_ERR(EINVAL);
} }
...@@ -1107,17 +1108,82 @@ static int mga_getparam( DRM_IOCTL_ARGS ) ...@@ -1107,17 +1108,82 @@ static int mga_getparam( DRM_IOCTL_ARGS )
return 0; return 0;
} }
static int mga_set_fence(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
u32 temp;
DMA_LOCALS;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
/* I would normal do this assignment in the declaration of temp,
* but dev_priv may be NULL.
*/
temp = dev_priv->next_fence_to_post;
dev_priv->next_fence_to_post++;
BEGIN_DMA(1);
DMA_BLOCK(MGA_DMAPAD, 0x00000000,
MGA_DMAPAD, 0x00000000,
MGA_DMAPAD, 0x00000000,
MGA_SOFTRAP, 0x00000000);
ADVANCE_DMA();
if (DRM_COPY_TO_USER( (u32 __user *) data, & temp, sizeof(u32))) {
DRM_ERROR("copy_to_user\n");
return DRM_ERR(EFAULT);
}
return 0;
}
static int mga_wait_fence(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
u32 fence;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(fence, (u32 __user *) data, sizeof(u32));
DRM_DEBUG("pid=%d\n", DRM_CURRENTPID);
mga_driver_fence_wait(dev, & fence);
if (DRM_COPY_TO_USER( (u32 __user *) data, & fence, sizeof(u32))) {
DRM_ERROR("copy_to_user\n");
return DRM_ERR(EFAULT);
}
return 0;
}
drm_ioctl_desc_t mga_ioctls[] = { drm_ioctl_desc_t mga_ioctls[] = {
[DRM_IOCTL_NR(DRM_MGA_INIT)] = { mga_dma_init, 1, 1 }, [DRM_IOCTL_NR(DRM_MGA_INIT)] = {mga_dma_init, 1, 1},
[DRM_IOCTL_NR(DRM_MGA_FLUSH)] = { mga_dma_flush, 1, 0 }, [DRM_IOCTL_NR(DRM_MGA_FLUSH)] = {mga_dma_flush, 1, 0},
[DRM_IOCTL_NR(DRM_MGA_RESET)] = { mga_dma_reset, 1, 0 }, [DRM_IOCTL_NR(DRM_MGA_RESET)] = {mga_dma_reset, 1, 0},
[DRM_IOCTL_NR(DRM_MGA_SWAP)] = { mga_dma_swap, 1, 0 }, [DRM_IOCTL_NR(DRM_MGA_SWAP)] = {mga_dma_swap, 1, 0},
[DRM_IOCTL_NR(DRM_MGA_CLEAR)] = { mga_dma_clear, 1, 0 }, [DRM_IOCTL_NR(DRM_MGA_CLEAR)] = {mga_dma_clear, 1, 0},
[DRM_IOCTL_NR(DRM_MGA_VERTEX)] = { mga_dma_vertex, 1, 0 }, [DRM_IOCTL_NR(DRM_MGA_VERTEX)] = {mga_dma_vertex, 1, 0},
[DRM_IOCTL_NR(DRM_MGA_INDICES)] = { mga_dma_indices, 1, 0 }, [DRM_IOCTL_NR(DRM_MGA_INDICES)] = {mga_dma_indices, 1, 0},
[DRM_IOCTL_NR(DRM_MGA_ILOAD)] = { mga_dma_iload, 1, 0 }, [DRM_IOCTL_NR(DRM_MGA_ILOAD)] = {mga_dma_iload, 1, 0},
[DRM_IOCTL_NR(DRM_MGA_BLIT)] = { mga_dma_blit, 1, 0 }, [DRM_IOCTL_NR(DRM_MGA_BLIT)] = {mga_dma_blit, 1, 0},
[DRM_IOCTL_NR(DRM_MGA_GETPARAM)]= { mga_getparam, 1, 0 }, [DRM_IOCTL_NR(DRM_MGA_GETPARAM)] = {mga_getparam, 1, 0},
[DRM_IOCTL_NR(DRM_MGA_SET_FENCE)] = {mga_set_fence, 1, 0},
[DRM_IOCTL_NR(DRM_MGA_WAIT_FENCE)] = {mga_wait_fence, 1, 0},
[DRM_IOCTL_NR(DRM_MGA_DMA_BOOTSTRAP)] = {mga_dma_bootstrap, 1, 1},
}; };
int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls); int mga_max_ioctl = DRM_ARRAY_SIZE(mga_ioctls);
...@@ -48,65 +48,52 @@ do { \ ...@@ -48,65 +48,52 @@ do { \
vcbase += WARP_UCODE_SIZE( which ); \ vcbase += WARP_UCODE_SIZE( which ); \
} while (0) } while (0)
static const unsigned int mga_warp_g400_microcode_size =
static unsigned int mga_warp_g400_microcode_size( drm_mga_private_t *dev_priv ) (WARP_UCODE_SIZE(warp_g400_tgz) +
{ WARP_UCODE_SIZE(warp_g400_tgza) +
unsigned int size; WARP_UCODE_SIZE(warp_g400_tgzaf) +
WARP_UCODE_SIZE(warp_g400_tgzf) +
size = ( WARP_UCODE_SIZE( warp_g400_tgz ) + WARP_UCODE_SIZE(warp_g400_tgzs) +
WARP_UCODE_SIZE( warp_g400_tgza ) + WARP_UCODE_SIZE(warp_g400_tgzsa) +
WARP_UCODE_SIZE( warp_g400_tgzaf ) + WARP_UCODE_SIZE(warp_g400_tgzsaf) +
WARP_UCODE_SIZE( warp_g400_tgzf ) + WARP_UCODE_SIZE(warp_g400_tgzsf) +
WARP_UCODE_SIZE( warp_g400_tgzs ) + WARP_UCODE_SIZE(warp_g400_t2gz) +
WARP_UCODE_SIZE( warp_g400_tgzsa ) + WARP_UCODE_SIZE(warp_g400_t2gza) +
WARP_UCODE_SIZE( warp_g400_tgzsaf ) + WARP_UCODE_SIZE(warp_g400_t2gzaf) +
WARP_UCODE_SIZE( warp_g400_tgzsf ) + WARP_UCODE_SIZE(warp_g400_t2gzf) +
WARP_UCODE_SIZE( warp_g400_t2gz ) + WARP_UCODE_SIZE(warp_g400_t2gzs) +
WARP_UCODE_SIZE( warp_g400_t2gza ) + WARP_UCODE_SIZE(warp_g400_t2gzsa) +
WARP_UCODE_SIZE( warp_g400_t2gzaf ) + WARP_UCODE_SIZE(warp_g400_t2gzsaf) +
WARP_UCODE_SIZE( warp_g400_t2gzf ) + WARP_UCODE_SIZE(warp_g400_t2gzsf));
WARP_UCODE_SIZE( warp_g400_t2gzs ) +
WARP_UCODE_SIZE( warp_g400_t2gzsa ) + static const unsigned int mga_warp_g200_microcode_size =
WARP_UCODE_SIZE( warp_g400_t2gzsaf ) + (WARP_UCODE_SIZE(warp_g200_tgz) +
WARP_UCODE_SIZE( warp_g400_t2gzsf ) ); WARP_UCODE_SIZE(warp_g200_tgza) +
WARP_UCODE_SIZE(warp_g200_tgzaf) +
size = PAGE_ALIGN( size ); WARP_UCODE_SIZE(warp_g200_tgzf) +
WARP_UCODE_SIZE(warp_g200_tgzs) +
DRM_DEBUG( "G400 ucode size = %d bytes\n", size ); WARP_UCODE_SIZE(warp_g200_tgzsa) +
return size; WARP_UCODE_SIZE(warp_g200_tgzsaf) +
} WARP_UCODE_SIZE(warp_g200_tgzsf));
static unsigned int mga_warp_g200_microcode_size( drm_mga_private_t *dev_priv )
unsigned int mga_warp_microcode_size(const drm_mga_private_t * dev_priv)
{ {
unsigned int size; switch (dev_priv->chipset) {
case MGA_CARD_TYPE_G400:
size = ( WARP_UCODE_SIZE( warp_g200_tgz ) + case MGA_CARD_TYPE_G550:
WARP_UCODE_SIZE( warp_g200_tgza ) + return PAGE_ALIGN(mga_warp_g400_microcode_size);
WARP_UCODE_SIZE( warp_g200_tgzaf ) + case MGA_CARD_TYPE_G200:
WARP_UCODE_SIZE( warp_g200_tgzf ) + return PAGE_ALIGN(mga_warp_g200_microcode_size);
WARP_UCODE_SIZE( warp_g200_tgzs ) + default:
WARP_UCODE_SIZE( warp_g200_tgzsa ) + return 0;
WARP_UCODE_SIZE( warp_g200_tgzsaf ) + }
WARP_UCODE_SIZE( warp_g200_tgzsf ) );
size = PAGE_ALIGN( size );
DRM_DEBUG( "G200 ucode size = %d bytes\n", size );
return size;
} }
static int mga_warp_install_g400_microcode( drm_mga_private_t *dev_priv ) static int mga_warp_install_g400_microcode( drm_mga_private_t *dev_priv )
{ {
unsigned char *vcbase = dev_priv->warp->handle; unsigned char *vcbase = dev_priv->warp->handle;
unsigned long pcbase = dev_priv->warp->offset; unsigned long pcbase = dev_priv->warp->offset;
unsigned int size;
size = mga_warp_g400_microcode_size( dev_priv );
if ( size > dev_priv->warp->size ) {
DRM_ERROR( "microcode too large! (%u > %lu)\n",
size, dev_priv->warp->size );
return DRM_ERR(ENOMEM);
}
memset( dev_priv->warp_pipe_phys, 0, memset( dev_priv->warp_pipe_phys, 0,
sizeof(dev_priv->warp_pipe_phys) ); sizeof(dev_priv->warp_pipe_phys) );
...@@ -136,35 +123,36 @@ static int mga_warp_install_g200_microcode( drm_mga_private_t *dev_priv ) ...@@ -136,35 +123,36 @@ static int mga_warp_install_g200_microcode( drm_mga_private_t *dev_priv )
{ {
unsigned char *vcbase = dev_priv->warp->handle; unsigned char *vcbase = dev_priv->warp->handle;
unsigned long pcbase = dev_priv->warp->offset; unsigned long pcbase = dev_priv->warp->offset;
unsigned int size;
size = mga_warp_g200_microcode_size( dev_priv );
if ( size > dev_priv->warp->size ) {
DRM_ERROR( "microcode too large! (%u > %lu)\n",
size, dev_priv->warp->size );
return DRM_ERR(ENOMEM);
}
memset( dev_priv->warp_pipe_phys, 0, memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys));
sizeof(dev_priv->warp_pipe_phys) );
WARP_UCODE_INSTALL( warp_g200_tgz, MGA_WARP_TGZ ); WARP_UCODE_INSTALL(warp_g200_tgz, MGA_WARP_TGZ);
WARP_UCODE_INSTALL( warp_g200_tgzf, MGA_WARP_TGZF ); WARP_UCODE_INSTALL(warp_g200_tgzf, MGA_WARP_TGZF);
WARP_UCODE_INSTALL( warp_g200_tgza, MGA_WARP_TGZA ); WARP_UCODE_INSTALL(warp_g200_tgza, MGA_WARP_TGZA);
WARP_UCODE_INSTALL( warp_g200_tgzaf, MGA_WARP_TGZAF ); WARP_UCODE_INSTALL(warp_g200_tgzaf, MGA_WARP_TGZAF);
WARP_UCODE_INSTALL( warp_g200_tgzs, MGA_WARP_TGZS ); WARP_UCODE_INSTALL(warp_g200_tgzs, MGA_WARP_TGZS);
WARP_UCODE_INSTALL( warp_g200_tgzsf, MGA_WARP_TGZSF ); WARP_UCODE_INSTALL(warp_g200_tgzsf, MGA_WARP_TGZSF);
WARP_UCODE_INSTALL( warp_g200_tgzsa, MGA_WARP_TGZSA ); WARP_UCODE_INSTALL(warp_g200_tgzsa, MGA_WARP_TGZSA);
WARP_UCODE_INSTALL( warp_g200_tgzsaf, MGA_WARP_TGZSAF ); WARP_UCODE_INSTALL(warp_g200_tgzsaf, MGA_WARP_TGZSAF);
return 0; return 0;
} }
int mga_warp_install_microcode( drm_mga_private_t *dev_priv ) int mga_warp_install_microcode( drm_mga_private_t *dev_priv )
{ {
switch ( dev_priv->chipset ) { const unsigned int size = mga_warp_microcode_size(dev_priv);
DRM_DEBUG("MGA ucode size = %d bytes\n", size);
if (size > dev_priv->warp->size) {
DRM_ERROR("microcode too large! (%u > %lu)\n",
size, dev_priv->warp->size);
return DRM_ERR(ENOMEM);
}
switch (dev_priv->chipset) {
case MGA_CARD_TYPE_G400: case MGA_CARD_TYPE_G400:
return mga_warp_install_g400_microcode( dev_priv ); case MGA_CARD_TYPE_G550:
return mga_warp_install_g400_microcode(dev_priv);
case MGA_CARD_TYPE_G200: case MGA_CARD_TYPE_G200:
return mga_warp_install_g200_microcode( dev_priv ); return mga_warp_install_g200_microcode( dev_priv );
default: default:
...@@ -182,10 +170,11 @@ int mga_warp_init( drm_mga_private_t *dev_priv ) ...@@ -182,10 +170,11 @@ int mga_warp_init( drm_mga_private_t *dev_priv )
*/ */
switch ( dev_priv->chipset ) { switch ( dev_priv->chipset ) {
case MGA_CARD_TYPE_G400: case MGA_CARD_TYPE_G400:
MGA_WRITE( MGA_WIADDR2, MGA_WMODE_SUSPEND ); case MGA_CARD_TYPE_G550:
MGA_WRITE( MGA_WGETMSB, 0x00000E00 ); MGA_WRITE(MGA_WIADDR2, MGA_WMODE_SUSPEND);
MGA_WRITE( MGA_WVRTXSZ, 0x00001807 ); MGA_WRITE(MGA_WGETMSB, 0x00000E00);
MGA_WRITE( MGA_WACCEPTSEQ, 0x18000000 ); MGA_WRITE(MGA_WVRTXSZ, 0x00001807);
MGA_WRITE(MGA_WACCEPTSEQ, 0x18000000);
break; break;
case MGA_CARD_TYPE_G200: case MGA_CARD_TYPE_G200:
MGA_WRITE( MGA_WIADDR, MGA_WMODE_SUSPEND ); MGA_WRITE( MGA_WIADDR, MGA_WMODE_SUSPEND );
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment