| /* mga_warp.c -- Matrox G200/G400 WARP engine management -*- linux-c -*- |
| * Created: Thu Jan 11 21:29:32 2001 by gareth@valinux.com |
| * |
| * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. |
| * All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * 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: |
| * Gareth Hughes <gareth@valinux.com> |
| */ |
| |
| #include "mga.h" |
| #include "drmP.h" |
| #include "drm.h" |
| #include "mga_drm.h" |
| #include "mga_drv.h" |
| #include "mga_ucode.h" |
| |
| |
| #define MGA_WARP_CODE_ALIGN 256 /* in bytes */ |
| |
| #define WARP_UCODE_SIZE( which ) \ |
| ((sizeof(which) / MGA_WARP_CODE_ALIGN + 1) * MGA_WARP_CODE_ALIGN) |
| |
| #define WARP_UCODE_INSTALL( which, where ) \ |
| do { \ |
| DRM_DEBUG( " pcbase = 0x%08lx vcbase = %p\n", pcbase, vcbase );\ |
| dev_priv->warp_pipe_phys[where] = pcbase; \ |
| memcpy( vcbase, which, sizeof(which) ); \ |
| pcbase += WARP_UCODE_SIZE( which ); \ |
| vcbase += WARP_UCODE_SIZE( which ); \ |
| } while (0) |
| |
| |
| static unsigned int mga_warp_g400_microcode_size( drm_mga_private_t *dev_priv ) |
| { |
| unsigned int size; |
| |
| size = ( WARP_UCODE_SIZE( warp_g400_tgz ) + |
| WARP_UCODE_SIZE( warp_g400_tgza ) + |
| WARP_UCODE_SIZE( warp_g400_tgzaf ) + |
| WARP_UCODE_SIZE( warp_g400_tgzf ) + |
| WARP_UCODE_SIZE( warp_g400_tgzs ) + |
| WARP_UCODE_SIZE( warp_g400_tgzsa ) + |
| WARP_UCODE_SIZE( warp_g400_tgzsaf ) + |
| WARP_UCODE_SIZE( warp_g400_tgzsf ) + |
| WARP_UCODE_SIZE( warp_g400_t2gz ) + |
| WARP_UCODE_SIZE( warp_g400_t2gza ) + |
| WARP_UCODE_SIZE( warp_g400_t2gzaf ) + |
| WARP_UCODE_SIZE( warp_g400_t2gzf ) + |
| WARP_UCODE_SIZE( warp_g400_t2gzs ) + |
| WARP_UCODE_SIZE( warp_g400_t2gzsa ) + |
| WARP_UCODE_SIZE( warp_g400_t2gzsaf ) + |
| WARP_UCODE_SIZE( warp_g400_t2gzsf ) ); |
| |
| size = PAGE_ALIGN( size ); |
| |
| DRM_DEBUG( "G400 ucode size = %d bytes\n", size ); |
| return size; |
| } |
| |
| static unsigned int mga_warp_g200_microcode_size( drm_mga_private_t *dev_priv ) |
| { |
| unsigned int size; |
| |
| size = ( WARP_UCODE_SIZE( warp_g200_tgz ) + |
| WARP_UCODE_SIZE( warp_g200_tgza ) + |
| WARP_UCODE_SIZE( warp_g200_tgzaf ) + |
| WARP_UCODE_SIZE( warp_g200_tgzf ) + |
| WARP_UCODE_SIZE( warp_g200_tgzs ) + |
| WARP_UCODE_SIZE( warp_g200_tgzsa ) + |
| 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 ) |
| { |
| unsigned char *vcbase = dev_priv->warp->handle; |
| 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, |
| sizeof(dev_priv->warp_pipe_phys) ); |
| |
| WARP_UCODE_INSTALL( warp_g400_tgz, MGA_WARP_TGZ ); |
| WARP_UCODE_INSTALL( warp_g400_tgzf, MGA_WARP_TGZF ); |
| WARP_UCODE_INSTALL( warp_g400_tgza, MGA_WARP_TGZA ); |
| WARP_UCODE_INSTALL( warp_g400_tgzaf, MGA_WARP_TGZAF ); |
| WARP_UCODE_INSTALL( warp_g400_tgzs, MGA_WARP_TGZS ); |
| WARP_UCODE_INSTALL( warp_g400_tgzsf, MGA_WARP_TGZSF ); |
| WARP_UCODE_INSTALL( warp_g400_tgzsa, MGA_WARP_TGZSA ); |
| WARP_UCODE_INSTALL( warp_g400_tgzsaf, MGA_WARP_TGZSAF ); |
| |
| WARP_UCODE_INSTALL( warp_g400_t2gz, MGA_WARP_T2GZ ); |
| WARP_UCODE_INSTALL( warp_g400_t2gzf, MGA_WARP_T2GZF ); |
| WARP_UCODE_INSTALL( warp_g400_t2gza, MGA_WARP_T2GZA ); |
| WARP_UCODE_INSTALL( warp_g400_t2gzaf, MGA_WARP_T2GZAF ); |
| WARP_UCODE_INSTALL( warp_g400_t2gzs, MGA_WARP_T2GZS ); |
| WARP_UCODE_INSTALL( warp_g400_t2gzsf, MGA_WARP_T2GZSF ); |
| WARP_UCODE_INSTALL( warp_g400_t2gzsa, MGA_WARP_T2GZSA ); |
| WARP_UCODE_INSTALL( warp_g400_t2gzsaf, MGA_WARP_T2GZSAF ); |
| |
| return 0; |
| } |
| |
| static int mga_warp_install_g200_microcode( drm_mga_private_t *dev_priv ) |
| { |
| unsigned char *vcbase = dev_priv->warp->handle; |
| 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, |
| sizeof(dev_priv->warp_pipe_phys) ); |
| |
| WARP_UCODE_INSTALL( warp_g200_tgz, MGA_WARP_TGZ ); |
| WARP_UCODE_INSTALL( warp_g200_tgzf, MGA_WARP_TGZF ); |
| WARP_UCODE_INSTALL( warp_g200_tgza, MGA_WARP_TGZA ); |
| WARP_UCODE_INSTALL( warp_g200_tgzaf, MGA_WARP_TGZAF ); |
| WARP_UCODE_INSTALL( warp_g200_tgzs, MGA_WARP_TGZS ); |
| WARP_UCODE_INSTALL( warp_g200_tgzsf, MGA_WARP_TGZSF ); |
| WARP_UCODE_INSTALL( warp_g200_tgzsa, MGA_WARP_TGZSA ); |
| WARP_UCODE_INSTALL( warp_g200_tgzsaf, MGA_WARP_TGZSAF ); |
| |
| return 0; |
| } |
| |
| int mga_warp_install_microcode( drm_mga_private_t *dev_priv ) |
| { |
| switch ( dev_priv->chipset ) { |
| case MGA_CARD_TYPE_G400: |
| return mga_warp_install_g400_microcode( dev_priv ); |
| case MGA_CARD_TYPE_G200: |
| return mga_warp_install_g200_microcode( dev_priv ); |
| default: |
| return DRM_ERR(EINVAL); |
| } |
| } |
| |
| #define WMISC_EXPECTED (MGA_WUCODECACHE_ENABLE | MGA_WMASTER_ENABLE) |
| |
| int mga_warp_init( drm_mga_private_t *dev_priv ) |
| { |
| u32 wmisc; |
| |
| /* FIXME: Get rid of these damned magic numbers... |
| */ |
| switch ( dev_priv->chipset ) { |
| case MGA_CARD_TYPE_G400: |
| MGA_WRITE( MGA_WIADDR2, MGA_WMODE_SUSPEND ); |
| MGA_WRITE( MGA_WGETMSB, 0x00000E00 ); |
| MGA_WRITE( MGA_WVRTXSZ, 0x00001807 ); |
| MGA_WRITE( MGA_WACCEPTSEQ, 0x18000000 ); |
| break; |
| case MGA_CARD_TYPE_G200: |
| MGA_WRITE( MGA_WIADDR, MGA_WMODE_SUSPEND ); |
| MGA_WRITE( MGA_WGETMSB, 0x1606 ); |
| MGA_WRITE( MGA_WVRTXSZ, 7 ); |
| break; |
| default: |
| return DRM_ERR(EINVAL); |
| } |
| |
| MGA_WRITE( MGA_WMISC, (MGA_WUCODECACHE_ENABLE | |
| MGA_WMASTER_ENABLE | |
| MGA_WCACHEFLUSH_ENABLE) ); |
| wmisc = MGA_READ( MGA_WMISC ); |
| if ( wmisc != WMISC_EXPECTED ) { |
| DRM_ERROR( "WARP engine config failed! 0x%x != 0x%x\n", |
| wmisc, WMISC_EXPECTED ); |
| return DRM_ERR(EINVAL); |
| } |
| |
| return 0; |
| } |