1 /* mga_warp.c -- Matrox G200/G400 WARP engine management -*- linux-c -*-
2  * Created: Thu Jan 11 21:29:32 2001 by gareth@valinux.com
3  *
4  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the next
15  * paragraph) shall be included in all copies or substantial portions of the
16  * Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  * OTHER DEALINGS IN THE SOFTWARE.
25  *
26  * Authors:
27  *    Gareth Hughes <gareth@valinux.com>
28  */
29 
30 
31 #include "mga.h"
32 #include "drmP.h"
33 #include "drm.h"
34 #include "mga_drm.h"
35 #include "mga_drv.h"
36 #include "mga_ucode.h"
37 
38 
39 #define MGA_WARP_CODE_ALIGN		256		/* in bytes */
40 
41 #define WARP_UCODE_SIZE( which )					\
42 	((sizeof(which) / MGA_WARP_CODE_ALIGN + 1) * MGA_WARP_CODE_ALIGN)
43 
44 #define WARP_UCODE_INSTALL( which, where )				\
45 do {									\
46 	DRM_DEBUG( " pcbase = 0x%08lx  vcbase = %p\n", pcbase, vcbase );\
47 	dev_priv->warp_pipe_phys[where] = pcbase;			\
48 	memcpy( vcbase, which, sizeof(which) );				\
49 	pcbase += WARP_UCODE_SIZE( which );				\
50 	vcbase += WARP_UCODE_SIZE( which );				\
51 } while (0)
52 
53 
mga_warp_g400_microcode_size(drm_mga_private_t * dev_priv)54 static unsigned int mga_warp_g400_microcode_size( drm_mga_private_t *dev_priv )
55 {
56 	unsigned int size;
57 
58 	size = ( WARP_UCODE_SIZE( warp_g400_tgz ) +
59 		 WARP_UCODE_SIZE( warp_g400_tgza ) +
60 		 WARP_UCODE_SIZE( warp_g400_tgzaf ) +
61 		 WARP_UCODE_SIZE( warp_g400_tgzf ) +
62 		 WARP_UCODE_SIZE( warp_g400_tgzs ) +
63 		 WARP_UCODE_SIZE( warp_g400_tgzsa ) +
64 		 WARP_UCODE_SIZE( warp_g400_tgzsaf ) +
65 		 WARP_UCODE_SIZE( warp_g400_tgzsf ) +
66 		 WARP_UCODE_SIZE( warp_g400_t2gz ) +
67 		 WARP_UCODE_SIZE( warp_g400_t2gza ) +
68 		 WARP_UCODE_SIZE( warp_g400_t2gzaf ) +
69 		 WARP_UCODE_SIZE( warp_g400_t2gzf ) +
70 		 WARP_UCODE_SIZE( warp_g400_t2gzs ) +
71 		 WARP_UCODE_SIZE( warp_g400_t2gzsa ) +
72 		 WARP_UCODE_SIZE( warp_g400_t2gzsaf ) +
73 		 WARP_UCODE_SIZE( warp_g400_t2gzsf ) );
74 
75 	size = PAGE_ALIGN( size );
76 
77 	DRM_DEBUG( "G400 ucode size = %d bytes\n", size );
78 	return size;
79 }
80 
mga_warp_g200_microcode_size(drm_mga_private_t * dev_priv)81 static unsigned int mga_warp_g200_microcode_size( drm_mga_private_t *dev_priv )
82 {
83 	unsigned int size;
84 
85 	size = ( WARP_UCODE_SIZE( warp_g200_tgz ) +
86 		 WARP_UCODE_SIZE( warp_g200_tgza ) +
87 		 WARP_UCODE_SIZE( warp_g200_tgzaf ) +
88 		 WARP_UCODE_SIZE( warp_g200_tgzf ) +
89 		 WARP_UCODE_SIZE( warp_g200_tgzs ) +
90 		 WARP_UCODE_SIZE( warp_g200_tgzsa ) +
91 		 WARP_UCODE_SIZE( warp_g200_tgzsaf ) +
92 		 WARP_UCODE_SIZE( warp_g200_tgzsf ) );
93 
94 	size = PAGE_ALIGN( size );
95 
96 	DRM_DEBUG( "G200 ucode size = %d bytes\n", size );
97 	return size;
98 }
99 
mga_warp_install_g400_microcode(drm_mga_private_t * dev_priv)100 static int mga_warp_install_g400_microcode( drm_mga_private_t *dev_priv )
101 {
102 	unsigned char *vcbase = dev_priv->warp->handle;
103 	unsigned long pcbase = dev_priv->warp->offset;
104 	unsigned int size;
105 
106 	size = mga_warp_g400_microcode_size( dev_priv );
107 	if ( size > dev_priv->warp->size ) {
108 		DRM_ERROR( "microcode too large! (%u > %lu)\n",
109 			   size, dev_priv->warp->size );
110 		return -ENOMEM;
111 	}
112 
113 	memset( dev_priv->warp_pipe_phys, 0,
114 		sizeof(dev_priv->warp_pipe_phys) );
115 
116 	WARP_UCODE_INSTALL( warp_g400_tgz,	MGA_WARP_TGZ );
117 	WARP_UCODE_INSTALL( warp_g400_tgzf,	MGA_WARP_TGZF );
118 	WARP_UCODE_INSTALL( warp_g400_tgza,	MGA_WARP_TGZA );
119 	WARP_UCODE_INSTALL( warp_g400_tgzaf,	MGA_WARP_TGZAF );
120 	WARP_UCODE_INSTALL( warp_g400_tgzs,	MGA_WARP_TGZS );
121 	WARP_UCODE_INSTALL( warp_g400_tgzsf,	MGA_WARP_TGZSF );
122 	WARP_UCODE_INSTALL( warp_g400_tgzsa,	MGA_WARP_TGZSA );
123 	WARP_UCODE_INSTALL( warp_g400_tgzsaf,	MGA_WARP_TGZSAF );
124 
125 	WARP_UCODE_INSTALL( warp_g400_t2gz,	MGA_WARP_T2GZ );
126 	WARP_UCODE_INSTALL( warp_g400_t2gzf,	MGA_WARP_T2GZF );
127 	WARP_UCODE_INSTALL( warp_g400_t2gza,	MGA_WARP_T2GZA );
128 	WARP_UCODE_INSTALL( warp_g400_t2gzaf,	MGA_WARP_T2GZAF );
129 	WARP_UCODE_INSTALL( warp_g400_t2gzs,	MGA_WARP_T2GZS );
130 	WARP_UCODE_INSTALL( warp_g400_t2gzsf,	MGA_WARP_T2GZSF );
131 	WARP_UCODE_INSTALL( warp_g400_t2gzsa,	MGA_WARP_T2GZSA );
132 	WARP_UCODE_INSTALL( warp_g400_t2gzsaf,	MGA_WARP_T2GZSAF );
133 
134 	return 0;
135 }
136 
mga_warp_install_g200_microcode(drm_mga_private_t * dev_priv)137 static int mga_warp_install_g200_microcode( drm_mga_private_t *dev_priv )
138 {
139 	unsigned char *vcbase = dev_priv->warp->handle;
140 	unsigned long pcbase = dev_priv->warp->offset;
141 	unsigned int size;
142 
143 	size = mga_warp_g200_microcode_size( dev_priv );
144 	if ( size > dev_priv->warp->size ) {
145 		DRM_ERROR( "microcode too large! (%u > %lu)\n",
146 			   size, dev_priv->warp->size );
147 		return -ENOMEM;
148 	}
149 
150 	memset( dev_priv->warp_pipe_phys, 0,
151 		sizeof(dev_priv->warp_pipe_phys) );
152 
153 	WARP_UCODE_INSTALL( warp_g200_tgz,	MGA_WARP_TGZ );
154 	WARP_UCODE_INSTALL( warp_g200_tgzf,	MGA_WARP_TGZF );
155 	WARP_UCODE_INSTALL( warp_g200_tgza,	MGA_WARP_TGZA );
156 	WARP_UCODE_INSTALL( warp_g200_tgzaf,	MGA_WARP_TGZAF );
157 	WARP_UCODE_INSTALL( warp_g200_tgzs,	MGA_WARP_TGZS );
158 	WARP_UCODE_INSTALL( warp_g200_tgzsf,	MGA_WARP_TGZSF );
159 	WARP_UCODE_INSTALL( warp_g200_tgzsa,	MGA_WARP_TGZSA );
160 	WARP_UCODE_INSTALL( warp_g200_tgzsaf,	MGA_WARP_TGZSAF );
161 
162 	return 0;
163 }
164 
mga_warp_install_microcode(drm_mga_private_t * dev_priv)165 int mga_warp_install_microcode(	drm_mga_private_t *dev_priv )
166 {
167 	switch ( dev_priv->chipset ) {
168 	case MGA_CARD_TYPE_G400:
169 		return mga_warp_install_g400_microcode( dev_priv );
170 	case MGA_CARD_TYPE_G200:
171 		return mga_warp_install_g200_microcode( dev_priv );
172 	default:
173 		return -EINVAL;
174 	}
175 }
176 
177 #define WMISC_EXPECTED		(MGA_WUCODECACHE_ENABLE | MGA_WMASTER_ENABLE)
178 
mga_warp_init(drm_mga_private_t * dev_priv)179 int mga_warp_init( drm_mga_private_t *dev_priv )
180 {
181 	u32 wmisc;
182 
183 	/* FIXME: Get rid of these damned magic numbers...
184 	 */
185 	switch ( dev_priv->chipset ) {
186 	case MGA_CARD_TYPE_G400:
187 		MGA_WRITE( MGA_WIADDR2, MGA_WMODE_SUSPEND );
188 		MGA_WRITE( MGA_WGETMSB, 0x00000E00 );
189 		MGA_WRITE( MGA_WVRTXSZ, 0x00001807 );
190 		MGA_WRITE( MGA_WACCEPTSEQ, 0x18000000 );
191 		break;
192 	case MGA_CARD_TYPE_G200:
193 		MGA_WRITE( MGA_WIADDR, MGA_WMODE_SUSPEND );
194 		MGA_WRITE( MGA_WGETMSB, 0x1606 );
195 		MGA_WRITE( MGA_WVRTXSZ, 7 );
196 		break;
197 	default:
198 		return -EINVAL;
199 	}
200 
201 	MGA_WRITE( MGA_WMISC, (MGA_WUCODECACHE_ENABLE |
202 			       MGA_WMASTER_ENABLE |
203 			       MGA_WCACHEFLUSH_ENABLE) );
204 	wmisc = MGA_READ( MGA_WMISC );
205 	if ( wmisc != WMISC_EXPECTED ) {
206 		DRM_ERROR( "WARP engine config failed! 0x%x != 0x%x\n",
207 			   wmisc, WMISC_EXPECTED );
208 		return -EINVAL;
209 	}
210 
211 	return 0;
212 }
213