Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* r128_cce.c -- ATI Rage 128 driver -*- linux-c -*- |
2 | * Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com | |
3 | * | |
4 | * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. | |
5 | * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. | |
6 | * All Rights Reserved. | |
7 | * | |
8 | * Permission is hereby granted, free of charge, to any person obtaining a | |
9 | * copy of this software and associated documentation files (the "Software"), | |
10 | * to deal in the Software without restriction, including without limitation | |
11 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
12 | * and/or sell copies of the Software, and to permit persons to whom the | |
13 | * Software is furnished to do so, subject to the following conditions: | |
14 | * | |
15 | * The above copyright notice and this permission notice (including the next | |
16 | * paragraph) shall be included in all copies or substantial portions of the | |
17 | * Software. | |
18 | * | |
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
22 | * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
25 | * DEALINGS IN THE SOFTWARE. | |
26 | * | |
27 | * Authors: | |
28 | * Gareth Hughes <gareth@valinux.com> | |
29 | */ | |
30 | ||
31 | #include "drmP.h" | |
32 | #include "drm.h" | |
33 | #include "r128_drm.h" | |
34 | #include "r128_drv.h" | |
35 | ||
36 | #define R128_FIFO_DEBUG 0 | |
37 | ||
38 | /* CCE microcode (from ATI) */ | |
39 | static u32 r128_cce_microcode[] = { | |
40 | 0, 276838400, 0, 268449792, 2, 142, 2, 145, 0, 1076765731, 0, | |
41 | 1617039951, 0, 774592877, 0, 1987540286, 0, 2307490946U, 0, | |
42 | 599558925, 0, 589505315, 0, 596487092, 0, 589505315, 1, | |
43 | 11544576, 1, 206848, 1, 311296, 1, 198656, 2, 912273422, 11, | |
44 | 262144, 0, 0, 1, 33559837, 1, 7438, 1, 14809, 1, 6615, 12, 28, | |
45 | 1, 6614, 12, 28, 2, 23, 11, 18874368, 0, 16790922, 1, 409600, 9, | |
46 | 30, 1, 147854772, 16, 420483072, 3, 8192, 0, 10240, 1, 198656, | |
47 | 1, 15630, 1, 51200, 10, 34858, 9, 42, 1, 33559823, 2, 10276, 1, | |
48 | 15717, 1, 15718, 2, 43, 1, 15936948, 1, 570480831, 1, 14715071, | |
49 | 12, 322123831, 1, 33953125, 12, 55, 1, 33559908, 1, 15718, 2, | |
50 | 46, 4, 2099258, 1, 526336, 1, 442623, 4, 4194365, 1, 509952, 1, | |
51 | 459007, 3, 0, 12, 92, 2, 46, 12, 176, 1, 15734, 1, 206848, 1, | |
52 | 18432, 1, 133120, 1, 100670734, 1, 149504, 1, 165888, 1, | |
53 | 15975928, 1, 1048576, 6, 3145806, 1, 15715, 16, 2150645232U, 2, | |
54 | 268449859, 2, 10307, 12, 176, 1, 15734, 1, 15735, 1, 15630, 1, | |
55 | 15631, 1, 5253120, 6, 3145810, 16, 2150645232U, 1, 15864, 2, 82, | |
56 | 1, 343310, 1, 1064207, 2, 3145813, 1, 15728, 1, 7817, 1, 15729, | |
57 | 3, 15730, 12, 92, 2, 98, 1, 16168, 1, 16167, 1, 16002, 1, 16008, | |
58 | 1, 15974, 1, 15975, 1, 15990, 1, 15976, 1, 15977, 1, 15980, 0, | |
59 | 15981, 1, 10240, 1, 5253120, 1, 15720, 1, 198656, 6, 110, 1, | |
60 | 180224, 1, 103824738, 2, 112, 2, 3145839, 0, 536885440, 1, | |
61 | 114880, 14, 125, 12, 206975, 1, 33559995, 12, 198784, 0, | |
62 | 33570236, 1, 15803, 0, 15804, 3, 294912, 1, 294912, 3, 442370, | |
63 | 1, 11544576, 0, 811612160, 1, 12593152, 1, 11536384, 1, | |
64 | 14024704, 7, 310382726, 0, 10240, 1, 14796, 1, 14797, 1, 14793, | |
65 | 1, 14794, 0, 14795, 1, 268679168, 1, 9437184, 1, 268449792, 1, | |
66 | 198656, 1, 9452827, 1, 1075854602, 1, 1075854603, 1, 557056, 1, | |
67 | 114880, 14, 159, 12, 198784, 1, 1109409213, 12, 198783, 1, | |
68 | 1107312059, 12, 198784, 1, 1109409212, 2, 162, 1, 1075854781, 1, | |
69 | 1073757627, 1, 1075854780, 1, 540672, 1, 10485760, 6, 3145894, | |
70 | 16, 274741248, 9, 168, 3, 4194304, 3, 4209949, 0, 0, 0, 256, 14, | |
71 | 174, 1, 114857, 1, 33560007, 12, 176, 0, 10240, 1, 114858, 1, | |
72 | 33560018, 1, 114857, 3, 33560007, 1, 16008, 1, 114874, 1, | |
73 | 33560360, 1, 114875, 1, 33560154, 0, 15963, 0, 256, 0, 4096, 1, | |
74 | 409611, 9, 188, 0, 10240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
75 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
76 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
77 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
78 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
79 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
80 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | |
81 | }; | |
82 | ||
83 | static int R128_READ_PLL(drm_device_t *dev, int addr) | |
84 | { | |
85 | drm_r128_private_t *dev_priv = dev->dev_private; | |
86 | ||
87 | R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f); | |
88 | return R128_READ(R128_CLOCK_CNTL_DATA); | |
89 | } | |
90 | ||
91 | #if R128_FIFO_DEBUG | |
92 | static void r128_status( drm_r128_private_t *dev_priv ) | |
93 | { | |
94 | printk( "GUI_STAT = 0x%08x\n", | |
95 | (unsigned int)R128_READ( R128_GUI_STAT ) ); | |
96 | printk( "PM4_STAT = 0x%08x\n", | |
97 | (unsigned int)R128_READ( R128_PM4_STAT ) ); | |
98 | printk( "PM4_BUFFER_DL_WPTR = 0x%08x\n", | |
99 | (unsigned int)R128_READ( R128_PM4_BUFFER_DL_WPTR ) ); | |
100 | printk( "PM4_BUFFER_DL_RPTR = 0x%08x\n", | |
101 | (unsigned int)R128_READ( R128_PM4_BUFFER_DL_RPTR ) ); | |
102 | printk( "PM4_MICRO_CNTL = 0x%08x\n", | |
103 | (unsigned int)R128_READ( R128_PM4_MICRO_CNTL ) ); | |
104 | printk( "PM4_BUFFER_CNTL = 0x%08x\n", | |
105 | (unsigned int)R128_READ( R128_PM4_BUFFER_CNTL ) ); | |
106 | } | |
107 | #endif | |
108 | ||
109 | ||
110 | /* ================================================================ | |
111 | * Engine, FIFO control | |
112 | */ | |
113 | ||
114 | static int r128_do_pixcache_flush( drm_r128_private_t *dev_priv ) | |
115 | { | |
116 | u32 tmp; | |
117 | int i; | |
118 | ||
119 | tmp = R128_READ( R128_PC_NGUI_CTLSTAT ) | R128_PC_FLUSH_ALL; | |
120 | R128_WRITE( R128_PC_NGUI_CTLSTAT, tmp ); | |
121 | ||
122 | for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { | |
123 | if ( !(R128_READ( R128_PC_NGUI_CTLSTAT ) & R128_PC_BUSY) ) { | |
124 | return 0; | |
125 | } | |
126 | DRM_UDELAY( 1 ); | |
127 | } | |
128 | ||
129 | #if R128_FIFO_DEBUG | |
130 | DRM_ERROR( "failed!\n" ); | |
131 | #endif | |
132 | return DRM_ERR(EBUSY); | |
133 | } | |
134 | ||
135 | static int r128_do_wait_for_fifo( drm_r128_private_t *dev_priv, int entries ) | |
136 | { | |
137 | int i; | |
138 | ||
139 | for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { | |
140 | int slots = R128_READ( R128_GUI_STAT ) & R128_GUI_FIFOCNT_MASK; | |
141 | if ( slots >= entries ) return 0; | |
142 | DRM_UDELAY( 1 ); | |
143 | } | |
144 | ||
145 | #if R128_FIFO_DEBUG | |
146 | DRM_ERROR( "failed!\n" ); | |
147 | #endif | |
148 | return DRM_ERR(EBUSY); | |
149 | } | |
150 | ||
151 | static int r128_do_wait_for_idle( drm_r128_private_t *dev_priv ) | |
152 | { | |
153 | int i, ret; | |
154 | ||
155 | ret = r128_do_wait_for_fifo( dev_priv, 64 ); | |
156 | if ( ret ) return ret; | |
157 | ||
158 | for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { | |
159 | if ( !(R128_READ( R128_GUI_STAT ) & R128_GUI_ACTIVE) ) { | |
160 | r128_do_pixcache_flush( dev_priv ); | |
161 | return 0; | |
162 | } | |
163 | DRM_UDELAY( 1 ); | |
164 | } | |
165 | ||
166 | #if R128_FIFO_DEBUG | |
167 | DRM_ERROR( "failed!\n" ); | |
168 | #endif | |
169 | return DRM_ERR(EBUSY); | |
170 | } | |
171 | ||
172 | ||
173 | /* ================================================================ | |
174 | * CCE control, initialization | |
175 | */ | |
176 | ||
177 | /* Load the microcode for the CCE */ | |
178 | static void r128_cce_load_microcode( drm_r128_private_t *dev_priv ) | |
179 | { | |
180 | int i; | |
181 | ||
182 | DRM_DEBUG( "\n" ); | |
183 | ||
184 | r128_do_wait_for_idle( dev_priv ); | |
185 | ||
186 | R128_WRITE( R128_PM4_MICROCODE_ADDR, 0 ); | |
187 | for ( i = 0 ; i < 256 ; i++ ) { | |
188 | R128_WRITE( R128_PM4_MICROCODE_DATAH, | |
189 | r128_cce_microcode[i * 2] ); | |
190 | R128_WRITE( R128_PM4_MICROCODE_DATAL, | |
191 | r128_cce_microcode[i * 2 + 1] ); | |
192 | } | |
193 | } | |
194 | ||
195 | /* Flush any pending commands to the CCE. This should only be used just | |
196 | * prior to a wait for idle, as it informs the engine that the command | |
197 | * stream is ending. | |
198 | */ | |
199 | static void r128_do_cce_flush( drm_r128_private_t *dev_priv ) | |
200 | { | |
201 | u32 tmp; | |
202 | ||
203 | tmp = R128_READ( R128_PM4_BUFFER_DL_WPTR ) | R128_PM4_BUFFER_DL_DONE; | |
204 | R128_WRITE( R128_PM4_BUFFER_DL_WPTR, tmp ); | |
205 | } | |
206 | ||
207 | /* Wait for the CCE to go idle. | |
208 | */ | |
209 | int r128_do_cce_idle( drm_r128_private_t *dev_priv ) | |
210 | { | |
211 | int i; | |
212 | ||
213 | for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { | |
214 | if ( GET_RING_HEAD( dev_priv ) == dev_priv->ring.tail ) { | |
215 | int pm4stat = R128_READ( R128_PM4_STAT ); | |
216 | if ( ( (pm4stat & R128_PM4_FIFOCNT_MASK) >= | |
217 | dev_priv->cce_fifo_size ) && | |
218 | !(pm4stat & (R128_PM4_BUSY | | |
219 | R128_PM4_GUI_ACTIVE)) ) { | |
220 | return r128_do_pixcache_flush( dev_priv ); | |
221 | } | |
222 | } | |
223 | DRM_UDELAY( 1 ); | |
224 | } | |
225 | ||
226 | #if R128_FIFO_DEBUG | |
227 | DRM_ERROR( "failed!\n" ); | |
228 | r128_status( dev_priv ); | |
229 | #endif | |
230 | return DRM_ERR(EBUSY); | |
231 | } | |
232 | ||
233 | /* Start the Concurrent Command Engine. | |
234 | */ | |
235 | static void r128_do_cce_start( drm_r128_private_t *dev_priv ) | |
236 | { | |
237 | r128_do_wait_for_idle( dev_priv ); | |
238 | ||
239 | R128_WRITE( R128_PM4_BUFFER_CNTL, | |
240 | dev_priv->cce_mode | dev_priv->ring.size_l2qw | |
241 | | R128_PM4_BUFFER_CNTL_NOUPDATE ); | |
242 | R128_READ( R128_PM4_BUFFER_ADDR ); /* as per the sample code */ | |
243 | R128_WRITE( R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN ); | |
244 | ||
245 | dev_priv->cce_running = 1; | |
246 | } | |
247 | ||
248 | /* Reset the Concurrent Command Engine. This will not flush any pending | |
249 | * commands, so you must wait for the CCE command stream to complete | |
250 | * before calling this routine. | |
251 | */ | |
252 | static void r128_do_cce_reset( drm_r128_private_t *dev_priv ) | |
253 | { | |
254 | R128_WRITE( R128_PM4_BUFFER_DL_WPTR, 0 ); | |
255 | R128_WRITE( R128_PM4_BUFFER_DL_RPTR, 0 ); | |
256 | dev_priv->ring.tail = 0; | |
257 | } | |
258 | ||
259 | /* Stop the Concurrent Command Engine. This will not flush any pending | |
260 | * commands, so you must flush the command stream and wait for the CCE | |
261 | * to go idle before calling this routine. | |
262 | */ | |
263 | static void r128_do_cce_stop( drm_r128_private_t *dev_priv ) | |
264 | { | |
265 | R128_WRITE( R128_PM4_MICRO_CNTL, 0 ); | |
266 | R128_WRITE( R128_PM4_BUFFER_CNTL, | |
267 | R128_PM4_NONPM4 | R128_PM4_BUFFER_CNTL_NOUPDATE ); | |
268 | ||
269 | dev_priv->cce_running = 0; | |
270 | } | |
271 | ||
272 | /* Reset the engine. This will stop the CCE if it is running. | |
273 | */ | |
274 | static int r128_do_engine_reset( drm_device_t *dev ) | |
275 | { | |
276 | drm_r128_private_t *dev_priv = dev->dev_private; | |
277 | u32 clock_cntl_index, mclk_cntl, gen_reset_cntl; | |
278 | ||
279 | r128_do_pixcache_flush( dev_priv ); | |
280 | ||
281 | clock_cntl_index = R128_READ( R128_CLOCK_CNTL_INDEX ); | |
282 | mclk_cntl = R128_READ_PLL( dev, R128_MCLK_CNTL ); | |
283 | ||
284 | R128_WRITE_PLL( R128_MCLK_CNTL, | |
285 | mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP ); | |
286 | ||
287 | gen_reset_cntl = R128_READ( R128_GEN_RESET_CNTL ); | |
288 | ||
289 | /* Taken from the sample code - do not change */ | |
290 | R128_WRITE( R128_GEN_RESET_CNTL, | |
291 | gen_reset_cntl | R128_SOFT_RESET_GUI ); | |
292 | R128_READ( R128_GEN_RESET_CNTL ); | |
293 | R128_WRITE( R128_GEN_RESET_CNTL, | |
294 | gen_reset_cntl & ~R128_SOFT_RESET_GUI ); | |
295 | R128_READ( R128_GEN_RESET_CNTL ); | |
296 | ||
297 | R128_WRITE_PLL( R128_MCLK_CNTL, mclk_cntl ); | |
298 | R128_WRITE( R128_CLOCK_CNTL_INDEX, clock_cntl_index ); | |
299 | R128_WRITE( R128_GEN_RESET_CNTL, gen_reset_cntl ); | |
300 | ||
301 | /* Reset the CCE ring */ | |
302 | r128_do_cce_reset( dev_priv ); | |
303 | ||
304 | /* The CCE is no longer running after an engine reset */ | |
305 | dev_priv->cce_running = 0; | |
306 | ||
307 | /* Reset any pending vertex, indirect buffers */ | |
308 | r128_freelist_reset( dev ); | |
309 | ||
310 | return 0; | |
311 | } | |
312 | ||
313 | static void r128_cce_init_ring_buffer( drm_device_t *dev, | |
314 | drm_r128_private_t *dev_priv ) | |
315 | { | |
316 | u32 ring_start; | |
317 | u32 tmp; | |
318 | ||
319 | DRM_DEBUG( "\n" ); | |
320 | ||
321 | /* The manual (p. 2) says this address is in "VM space". This | |
322 | * means it's an offset from the start of AGP space. | |
323 | */ | |
324 | #if __OS_HAS_AGP | |
325 | if ( !dev_priv->is_pci ) | |
326 | ring_start = dev_priv->cce_ring->offset - dev->agp->base; | |
327 | else | |
328 | #endif | |
d1f2b55a DA |
329 | ring_start = dev_priv->cce_ring->offset - |
330 | (unsigned long)dev->sg->virtual; | |
1da177e4 LT |
331 | |
332 | R128_WRITE( R128_PM4_BUFFER_OFFSET, ring_start | R128_AGP_OFFSET ); | |
333 | ||
334 | R128_WRITE( R128_PM4_BUFFER_DL_WPTR, 0 ); | |
335 | R128_WRITE( R128_PM4_BUFFER_DL_RPTR, 0 ); | |
336 | ||
337 | /* Set watermark control */ | |
338 | R128_WRITE( R128_PM4_BUFFER_WM_CNTL, | |
339 | ((R128_WATERMARK_L/4) << R128_WMA_SHIFT) | |
340 | | ((R128_WATERMARK_M/4) << R128_WMB_SHIFT) | |
341 | | ((R128_WATERMARK_N/4) << R128_WMC_SHIFT) | |
342 | | ((R128_WATERMARK_K/64) << R128_WB_WM_SHIFT) ); | |
343 | ||
344 | /* Force read. Why? Because it's in the examples... */ | |
345 | R128_READ( R128_PM4_BUFFER_ADDR ); | |
346 | ||
347 | /* Turn on bus mastering */ | |
348 | tmp = R128_READ( R128_BUS_CNTL ) & ~R128_BUS_MASTER_DIS; | |
349 | R128_WRITE( R128_BUS_CNTL, tmp ); | |
350 | } | |
351 | ||
352 | static int r128_do_init_cce( drm_device_t *dev, drm_r128_init_t *init ) | |
353 | { | |
354 | drm_r128_private_t *dev_priv; | |
355 | ||
356 | DRM_DEBUG( "\n" ); | |
357 | ||
358 | dev_priv = drm_alloc( sizeof(drm_r128_private_t), DRM_MEM_DRIVER ); | |
359 | if ( dev_priv == NULL ) | |
360 | return DRM_ERR(ENOMEM); | |
361 | ||
362 | memset( dev_priv, 0, sizeof(drm_r128_private_t) ); | |
363 | ||
364 | dev_priv->is_pci = init->is_pci; | |
365 | ||
366 | if ( dev_priv->is_pci && !dev->sg ) { | |
367 | DRM_ERROR( "PCI GART memory not allocated!\n" ); | |
368 | dev->dev_private = (void *)dev_priv; | |
369 | r128_do_cleanup_cce( dev ); | |
370 | return DRM_ERR(EINVAL); | |
371 | } | |
372 | ||
373 | dev_priv->usec_timeout = init->usec_timeout; | |
374 | if ( dev_priv->usec_timeout < 1 || | |
375 | dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT ) { | |
376 | DRM_DEBUG( "TIMEOUT problem!\n" ); | |
377 | dev->dev_private = (void *)dev_priv; | |
378 | r128_do_cleanup_cce( dev ); | |
379 | return DRM_ERR(EINVAL); | |
380 | } | |
381 | ||
382 | dev_priv->cce_mode = init->cce_mode; | |
383 | ||
384 | /* GH: Simple idle check. | |
385 | */ | |
386 | atomic_set( &dev_priv->idle_count, 0 ); | |
387 | ||
388 | /* We don't support anything other than bus-mastering ring mode, | |
389 | * but the ring can be in either AGP or PCI space for the ring | |
390 | * read pointer. | |
391 | */ | |
392 | if ( ( init->cce_mode != R128_PM4_192BM ) && | |
393 | ( init->cce_mode != R128_PM4_128BM_64INDBM ) && | |
394 | ( init->cce_mode != R128_PM4_64BM_128INDBM ) && | |
395 | ( init->cce_mode != R128_PM4_64BM_64VCBM_64INDBM ) ) { | |
396 | DRM_DEBUG( "Bad cce_mode!\n" ); | |
397 | dev->dev_private = (void *)dev_priv; | |
398 | r128_do_cleanup_cce( dev ); | |
399 | return DRM_ERR(EINVAL); | |
400 | } | |
401 | ||
402 | switch ( init->cce_mode ) { | |
403 | case R128_PM4_NONPM4: | |
404 | dev_priv->cce_fifo_size = 0; | |
405 | break; | |
406 | case R128_PM4_192PIO: | |
407 | case R128_PM4_192BM: | |
408 | dev_priv->cce_fifo_size = 192; | |
409 | break; | |
410 | case R128_PM4_128PIO_64INDBM: | |
411 | case R128_PM4_128BM_64INDBM: | |
412 | dev_priv->cce_fifo_size = 128; | |
413 | break; | |
414 | case R128_PM4_64PIO_128INDBM: | |
415 | case R128_PM4_64BM_128INDBM: | |
416 | case R128_PM4_64PIO_64VCBM_64INDBM: | |
417 | case R128_PM4_64BM_64VCBM_64INDBM: | |
418 | case R128_PM4_64PIO_64VCPIO_64INDPIO: | |
419 | dev_priv->cce_fifo_size = 64; | |
420 | break; | |
421 | } | |
422 | ||
423 | switch ( init->fb_bpp ) { | |
424 | case 16: | |
425 | dev_priv->color_fmt = R128_DATATYPE_RGB565; | |
426 | break; | |
427 | case 32: | |
428 | default: | |
429 | dev_priv->color_fmt = R128_DATATYPE_ARGB8888; | |
430 | break; | |
431 | } | |
432 | dev_priv->front_offset = init->front_offset; | |
433 | dev_priv->front_pitch = init->front_pitch; | |
434 | dev_priv->back_offset = init->back_offset; | |
435 | dev_priv->back_pitch = init->back_pitch; | |
436 | ||
437 | switch ( init->depth_bpp ) { | |
438 | case 16: | |
439 | dev_priv->depth_fmt = R128_DATATYPE_RGB565; | |
440 | break; | |
441 | case 24: | |
442 | case 32: | |
443 | default: | |
444 | dev_priv->depth_fmt = R128_DATATYPE_ARGB8888; | |
445 | break; | |
446 | } | |
447 | dev_priv->depth_offset = init->depth_offset; | |
448 | dev_priv->depth_pitch = init->depth_pitch; | |
449 | dev_priv->span_offset = init->span_offset; | |
450 | ||
451 | dev_priv->front_pitch_offset_c = (((dev_priv->front_pitch/8) << 21) | | |
452 | (dev_priv->front_offset >> 5)); | |
453 | dev_priv->back_pitch_offset_c = (((dev_priv->back_pitch/8) << 21) | | |
454 | (dev_priv->back_offset >> 5)); | |
455 | dev_priv->depth_pitch_offset_c = (((dev_priv->depth_pitch/8) << 21) | | |
456 | (dev_priv->depth_offset >> 5) | | |
457 | R128_DST_TILE); | |
458 | dev_priv->span_pitch_offset_c = (((dev_priv->depth_pitch/8) << 21) | | |
459 | (dev_priv->span_offset >> 5)); | |
460 | ||
461 | DRM_GETSAREA(); | |
462 | ||
463 | if(!dev_priv->sarea) { | |
464 | DRM_ERROR("could not find sarea!\n"); | |
465 | dev->dev_private = (void *)dev_priv; | |
466 | r128_do_cleanup_cce( dev ); | |
467 | return DRM_ERR(EINVAL); | |
468 | } | |
469 | ||
470 | dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); | |
471 | if(!dev_priv->mmio) { | |
472 | DRM_ERROR("could not find mmio region!\n"); | |
473 | dev->dev_private = (void *)dev_priv; | |
474 | r128_do_cleanup_cce( dev ); | |
475 | return DRM_ERR(EINVAL); | |
476 | } | |
477 | dev_priv->cce_ring = drm_core_findmap(dev, init->ring_offset); | |
478 | if(!dev_priv->cce_ring) { | |
479 | DRM_ERROR("could not find cce ring region!\n"); | |
480 | dev->dev_private = (void *)dev_priv; | |
481 | r128_do_cleanup_cce( dev ); | |
482 | return DRM_ERR(EINVAL); | |
483 | } | |
484 | dev_priv->ring_rptr = drm_core_findmap(dev, init->ring_rptr_offset); | |
485 | if(!dev_priv->ring_rptr) { | |
486 | DRM_ERROR("could not find ring read pointer!\n"); | |
487 | dev->dev_private = (void *)dev_priv; | |
488 | r128_do_cleanup_cce( dev ); | |
489 | return DRM_ERR(EINVAL); | |
490 | } | |
d1f2b55a | 491 | dev->agp_buffer_token = init->buffers_offset; |
1da177e4 LT |
492 | dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset); |
493 | if(!dev->agp_buffer_map) { | |
494 | DRM_ERROR("could not find dma buffer region!\n"); | |
495 | dev->dev_private = (void *)dev_priv; | |
496 | r128_do_cleanup_cce( dev ); | |
497 | return DRM_ERR(EINVAL); | |
498 | } | |
499 | ||
500 | if ( !dev_priv->is_pci ) { | |
501 | dev_priv->agp_textures = drm_core_findmap(dev, init->agp_textures_offset); | |
502 | if(!dev_priv->agp_textures) { | |
503 | DRM_ERROR("could not find agp texture region!\n"); | |
504 | dev->dev_private = (void *)dev_priv; | |
505 | r128_do_cleanup_cce( dev ); | |
506 | return DRM_ERR(EINVAL); | |
507 | } | |
508 | } | |
509 | ||
510 | dev_priv->sarea_priv = | |
511 | (drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle + | |
512 | init->sarea_priv_offset); | |
513 | ||
514 | #if __OS_HAS_AGP | |
515 | if ( !dev_priv->is_pci ) { | |
516 | drm_core_ioremap( dev_priv->cce_ring, dev ); | |
517 | drm_core_ioremap( dev_priv->ring_rptr, dev ); | |
518 | drm_core_ioremap( dev->agp_buffer_map, dev ); | |
519 | if(!dev_priv->cce_ring->handle || | |
520 | !dev_priv->ring_rptr->handle || | |
521 | !dev->agp_buffer_map->handle) { | |
522 | DRM_ERROR("Could not ioremap agp regions!\n"); | |
523 | dev->dev_private = (void *)dev_priv; | |
524 | r128_do_cleanup_cce( dev ); | |
525 | return DRM_ERR(ENOMEM); | |
526 | } | |
527 | } else | |
528 | #endif | |
529 | { | |
530 | dev_priv->cce_ring->handle = | |
531 | (void *)dev_priv->cce_ring->offset; | |
532 | dev_priv->ring_rptr->handle = | |
533 | (void *)dev_priv->ring_rptr->offset; | |
534 | dev->agp_buffer_map->handle = (void *)dev->agp_buffer_map->offset; | |
535 | } | |
536 | ||
537 | #if __OS_HAS_AGP | |
538 | if ( !dev_priv->is_pci ) | |
539 | dev_priv->cce_buffers_offset = dev->agp->base; | |
540 | else | |
541 | #endif | |
d1f2b55a | 542 | dev_priv->cce_buffers_offset = (unsigned long)dev->sg->virtual; |
1da177e4 LT |
543 | |
544 | dev_priv->ring.start = (u32 *)dev_priv->cce_ring->handle; | |
545 | dev_priv->ring.end = ((u32 *)dev_priv->cce_ring->handle | |
546 | + init->ring_size / sizeof(u32)); | |
547 | dev_priv->ring.size = init->ring_size; | |
548 | dev_priv->ring.size_l2qw = drm_order( init->ring_size / 8 ); | |
549 | ||
550 | dev_priv->ring.tail_mask = | |
551 | (dev_priv->ring.size / sizeof(u32)) - 1; | |
552 | ||
553 | dev_priv->ring.high_mark = 128; | |
554 | ||
555 | dev_priv->sarea_priv->last_frame = 0; | |
556 | R128_WRITE( R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame ); | |
557 | ||
558 | dev_priv->sarea_priv->last_dispatch = 0; | |
559 | R128_WRITE( R128_LAST_DISPATCH_REG, | |
560 | dev_priv->sarea_priv->last_dispatch ); | |
561 | ||
562 | #if __OS_HAS_AGP | |
563 | if ( dev_priv->is_pci ) { | |
564 | #endif | |
565 | if (!drm_ati_pcigart_init( dev, &dev_priv->phys_pci_gart, | |
566 | &dev_priv->bus_pci_gart) ) { | |
567 | DRM_ERROR( "failed to init PCI GART!\n" ); | |
568 | dev->dev_private = (void *)dev_priv; | |
569 | r128_do_cleanup_cce( dev ); | |
570 | return DRM_ERR(ENOMEM); | |
571 | } | |
572 | R128_WRITE( R128_PCI_GART_PAGE, dev_priv->bus_pci_gart ); | |
573 | #if __OS_HAS_AGP | |
574 | } | |
575 | #endif | |
576 | ||
577 | r128_cce_init_ring_buffer( dev, dev_priv ); | |
578 | r128_cce_load_microcode( dev_priv ); | |
579 | ||
580 | dev->dev_private = (void *)dev_priv; | |
581 | ||
582 | r128_do_engine_reset( dev ); | |
583 | ||
584 | return 0; | |
585 | } | |
586 | ||
587 | int r128_do_cleanup_cce( drm_device_t *dev ) | |
588 | { | |
589 | ||
590 | /* Make sure interrupts are disabled here because the uninstall ioctl | |
591 | * may not have been called from userspace and after dev_private | |
592 | * is freed, it's too late. | |
593 | */ | |
594 | if ( dev->irq_enabled ) drm_irq_uninstall(dev); | |
595 | ||
596 | if ( dev->dev_private ) { | |
597 | drm_r128_private_t *dev_priv = dev->dev_private; | |
598 | ||
599 | #if __OS_HAS_AGP | |
600 | if ( !dev_priv->is_pci ) { | |
601 | if ( dev_priv->cce_ring != NULL ) | |
602 | drm_core_ioremapfree( dev_priv->cce_ring, dev ); | |
603 | if ( dev_priv->ring_rptr != NULL ) | |
604 | drm_core_ioremapfree( dev_priv->ring_rptr, dev ); | |
605 | if ( dev->agp_buffer_map != NULL ) | |
606 | drm_core_ioremapfree( dev->agp_buffer_map, dev ); | |
607 | } else | |
608 | #endif | |
609 | { | |
610 | if (!drm_ati_pcigart_cleanup( dev, | |
611 | dev_priv->phys_pci_gart, | |
612 | dev_priv->bus_pci_gart )) | |
613 | DRM_ERROR( "failed to cleanup PCI GART!\n" ); | |
614 | } | |
615 | ||
616 | drm_free( dev->dev_private, sizeof(drm_r128_private_t), | |
617 | DRM_MEM_DRIVER ); | |
618 | dev->dev_private = NULL; | |
619 | } | |
620 | ||
621 | return 0; | |
622 | } | |
623 | ||
624 | int r128_cce_init( DRM_IOCTL_ARGS ) | |
625 | { | |
626 | DRM_DEVICE; | |
627 | drm_r128_init_t init; | |
628 | ||
629 | DRM_DEBUG( "\n" ); | |
630 | ||
631 | LOCK_TEST_WITH_RETURN( dev, filp ); | |
632 | ||
633 | DRM_COPY_FROM_USER_IOCTL( init, (drm_r128_init_t __user *)data, sizeof(init) ); | |
634 | ||
635 | switch ( init.func ) { | |
636 | case R128_INIT_CCE: | |
637 | return r128_do_init_cce( dev, &init ); | |
638 | case R128_CLEANUP_CCE: | |
639 | return r128_do_cleanup_cce( dev ); | |
640 | } | |
641 | ||
642 | return DRM_ERR(EINVAL); | |
643 | } | |
644 | ||
645 | int r128_cce_start( DRM_IOCTL_ARGS ) | |
646 | { | |
647 | DRM_DEVICE; | |
648 | drm_r128_private_t *dev_priv = dev->dev_private; | |
649 | DRM_DEBUG( "\n" ); | |
650 | ||
651 | LOCK_TEST_WITH_RETURN( dev, filp ); | |
652 | ||
653 | if ( dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4 ) { | |
654 | DRM_DEBUG( "%s while CCE running\n", __FUNCTION__ ); | |
655 | return 0; | |
656 | } | |
657 | ||
658 | r128_do_cce_start( dev_priv ); | |
659 | ||
660 | return 0; | |
661 | } | |
662 | ||
663 | /* Stop the CCE. The engine must have been idled before calling this | |
664 | * routine. | |
665 | */ | |
666 | int r128_cce_stop( DRM_IOCTL_ARGS ) | |
667 | { | |
668 | DRM_DEVICE; | |
669 | drm_r128_private_t *dev_priv = dev->dev_private; | |
670 | drm_r128_cce_stop_t stop; | |
671 | int ret; | |
672 | DRM_DEBUG( "\n" ); | |
673 | ||
674 | LOCK_TEST_WITH_RETURN( dev, filp ); | |
675 | ||
676 | DRM_COPY_FROM_USER_IOCTL(stop, (drm_r128_cce_stop_t __user *)data, sizeof(stop) ); | |
677 | ||
678 | /* Flush any pending CCE commands. This ensures any outstanding | |
679 | * commands are exectuted by the engine before we turn it off. | |
680 | */ | |
681 | if ( stop.flush ) { | |
682 | r128_do_cce_flush( dev_priv ); | |
683 | } | |
684 | ||
685 | /* If we fail to make the engine go idle, we return an error | |
686 | * code so that the DRM ioctl wrapper can try again. | |
687 | */ | |
688 | if ( stop.idle ) { | |
689 | ret = r128_do_cce_idle( dev_priv ); | |
690 | if ( ret ) return ret; | |
691 | } | |
692 | ||
693 | /* Finally, we can turn off the CCE. If the engine isn't idle, | |
694 | * we will get some dropped triangles as they won't be fully | |
695 | * rendered before the CCE is shut down. | |
696 | */ | |
697 | r128_do_cce_stop( dev_priv ); | |
698 | ||
699 | /* Reset the engine */ | |
700 | r128_do_engine_reset( dev ); | |
701 | ||
702 | return 0; | |
703 | } | |
704 | ||
705 | /* Just reset the CCE ring. Called as part of an X Server engine reset. | |
706 | */ | |
707 | int r128_cce_reset( DRM_IOCTL_ARGS ) | |
708 | { | |
709 | DRM_DEVICE; | |
710 | drm_r128_private_t *dev_priv = dev->dev_private; | |
711 | DRM_DEBUG( "\n" ); | |
712 | ||
713 | LOCK_TEST_WITH_RETURN( dev, filp ); | |
714 | ||
715 | if ( !dev_priv ) { | |
716 | DRM_DEBUG( "%s called before init done\n", __FUNCTION__ ); | |
717 | return DRM_ERR(EINVAL); | |
718 | } | |
719 | ||
720 | r128_do_cce_reset( dev_priv ); | |
721 | ||
722 | /* The CCE is no longer running after an engine reset */ | |
723 | dev_priv->cce_running = 0; | |
724 | ||
725 | return 0; | |
726 | } | |
727 | ||
728 | int r128_cce_idle( DRM_IOCTL_ARGS ) | |
729 | { | |
730 | DRM_DEVICE; | |
731 | drm_r128_private_t *dev_priv = dev->dev_private; | |
732 | DRM_DEBUG( "\n" ); | |
733 | ||
734 | LOCK_TEST_WITH_RETURN( dev, filp ); | |
735 | ||
736 | if ( dev_priv->cce_running ) { | |
737 | r128_do_cce_flush( dev_priv ); | |
738 | } | |
739 | ||
740 | return r128_do_cce_idle( dev_priv ); | |
741 | } | |
742 | ||
743 | int r128_engine_reset( DRM_IOCTL_ARGS ) | |
744 | { | |
745 | DRM_DEVICE; | |
746 | DRM_DEBUG( "\n" ); | |
747 | ||
748 | LOCK_TEST_WITH_RETURN( dev, filp ); | |
749 | ||
750 | return r128_do_engine_reset( dev ); | |
751 | } | |
752 | ||
753 | int r128_fullscreen( DRM_IOCTL_ARGS ) | |
754 | { | |
755 | return DRM_ERR(EINVAL); | |
756 | } | |
757 | ||
758 | ||
759 | /* ================================================================ | |
760 | * Freelist management | |
761 | */ | |
762 | #define R128_BUFFER_USED 0xffffffff | |
763 | #define R128_BUFFER_FREE 0 | |
764 | ||
765 | #if 0 | |
766 | static int r128_freelist_init( drm_device_t *dev ) | |
767 | { | |
768 | drm_device_dma_t *dma = dev->dma; | |
769 | drm_r128_private_t *dev_priv = dev->dev_private; | |
770 | drm_buf_t *buf; | |
771 | drm_r128_buf_priv_t *buf_priv; | |
772 | drm_r128_freelist_t *entry; | |
773 | int i; | |
774 | ||
775 | dev_priv->head = drm_alloc( sizeof(drm_r128_freelist_t), | |
776 | DRM_MEM_DRIVER ); | |
777 | if ( dev_priv->head == NULL ) | |
778 | return DRM_ERR(ENOMEM); | |
779 | ||
780 | memset( dev_priv->head, 0, sizeof(drm_r128_freelist_t) ); | |
781 | dev_priv->head->age = R128_BUFFER_USED; | |
782 | ||
783 | for ( i = 0 ; i < dma->buf_count ; i++ ) { | |
784 | buf = dma->buflist[i]; | |
785 | buf_priv = buf->dev_private; | |
786 | ||
787 | entry = drm_alloc( sizeof(drm_r128_freelist_t), | |
788 | DRM_MEM_DRIVER ); | |
789 | if ( !entry ) return DRM_ERR(ENOMEM); | |
790 | ||
791 | entry->age = R128_BUFFER_FREE; | |
792 | entry->buf = buf; | |
793 | entry->prev = dev_priv->head; | |
794 | entry->next = dev_priv->head->next; | |
795 | if ( !entry->next ) | |
796 | dev_priv->tail = entry; | |
797 | ||
798 | buf_priv->discard = 0; | |
799 | buf_priv->dispatched = 0; | |
800 | buf_priv->list_entry = entry; | |
801 | ||
802 | dev_priv->head->next = entry; | |
803 | ||
804 | if ( dev_priv->head->next ) | |
805 | dev_priv->head->next->prev = entry; | |
806 | } | |
807 | ||
808 | return 0; | |
809 | ||
810 | } | |
811 | #endif | |
812 | ||
813 | static drm_buf_t *r128_freelist_get( drm_device_t *dev ) | |
814 | { | |
815 | drm_device_dma_t *dma = dev->dma; | |
816 | drm_r128_private_t *dev_priv = dev->dev_private; | |
817 | drm_r128_buf_priv_t *buf_priv; | |
818 | drm_buf_t *buf; | |
819 | int i, t; | |
820 | ||
821 | /* FIXME: Optimize -- use freelist code */ | |
822 | ||
823 | for ( i = 0 ; i < dma->buf_count ; i++ ) { | |
824 | buf = dma->buflist[i]; | |
825 | buf_priv = buf->dev_private; | |
826 | if ( buf->filp == 0 ) | |
827 | return buf; | |
828 | } | |
829 | ||
830 | for ( t = 0 ; t < dev_priv->usec_timeout ; t++ ) { | |
831 | u32 done_age = R128_READ( R128_LAST_DISPATCH_REG ); | |
832 | ||
833 | for ( i = 0 ; i < dma->buf_count ; i++ ) { | |
834 | buf = dma->buflist[i]; | |
835 | buf_priv = buf->dev_private; | |
836 | if ( buf->pending && buf_priv->age <= done_age ) { | |
837 | /* The buffer has been processed, so it | |
838 | * can now be used. | |
839 | */ | |
840 | buf->pending = 0; | |
841 | return buf; | |
842 | } | |
843 | } | |
844 | DRM_UDELAY( 1 ); | |
845 | } | |
846 | ||
847 | DRM_DEBUG( "returning NULL!\n" ); | |
848 | return NULL; | |
849 | } | |
850 | ||
851 | void r128_freelist_reset( drm_device_t *dev ) | |
852 | { | |
853 | drm_device_dma_t *dma = dev->dma; | |
854 | int i; | |
855 | ||
856 | for ( i = 0 ; i < dma->buf_count ; i++ ) { | |
857 | drm_buf_t *buf = dma->buflist[i]; | |
858 | drm_r128_buf_priv_t *buf_priv = buf->dev_private; | |
859 | buf_priv->age = 0; | |
860 | } | |
861 | } | |
862 | ||
863 | ||
864 | /* ================================================================ | |
865 | * CCE command submission | |
866 | */ | |
867 | ||
868 | int r128_wait_ring( drm_r128_private_t *dev_priv, int n ) | |
869 | { | |
870 | drm_r128_ring_buffer_t *ring = &dev_priv->ring; | |
871 | int i; | |
872 | ||
873 | for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { | |
874 | r128_update_ring_snapshot( dev_priv ); | |
875 | if ( ring->space >= n ) | |
876 | return 0; | |
877 | DRM_UDELAY( 1 ); | |
878 | } | |
879 | ||
880 | /* FIXME: This is being ignored... */ | |
881 | DRM_ERROR( "failed!\n" ); | |
882 | return DRM_ERR(EBUSY); | |
883 | } | |
884 | ||
885 | static int r128_cce_get_buffers( DRMFILE filp, drm_device_t *dev, drm_dma_t *d ) | |
886 | { | |
887 | int i; | |
888 | drm_buf_t *buf; | |
889 | ||
890 | for ( i = d->granted_count ; i < d->request_count ; i++ ) { | |
891 | buf = r128_freelist_get( dev ); | |
892 | if ( !buf ) return DRM_ERR(EAGAIN); | |
893 | ||
894 | buf->filp = filp; | |
895 | ||
896 | if ( DRM_COPY_TO_USER( &d->request_indices[i], &buf->idx, | |
897 | sizeof(buf->idx) ) ) | |
898 | return DRM_ERR(EFAULT); | |
899 | if ( DRM_COPY_TO_USER( &d->request_sizes[i], &buf->total, | |
900 | sizeof(buf->total) ) ) | |
901 | return DRM_ERR(EFAULT); | |
902 | ||
903 | d->granted_count++; | |
904 | } | |
905 | return 0; | |
906 | } | |
907 | ||
908 | int r128_cce_buffers( DRM_IOCTL_ARGS ) | |
909 | { | |
910 | DRM_DEVICE; | |
911 | drm_device_dma_t *dma = dev->dma; | |
912 | int ret = 0; | |
913 | drm_dma_t __user *argp = (void __user *)data; | |
914 | drm_dma_t d; | |
915 | ||
916 | LOCK_TEST_WITH_RETURN( dev, filp ); | |
917 | ||
918 | DRM_COPY_FROM_USER_IOCTL( d, argp, sizeof(d) ); | |
919 | ||
920 | /* Please don't send us buffers. | |
921 | */ | |
922 | if ( d.send_count != 0 ) { | |
923 | DRM_ERROR( "Process %d trying to send %d buffers via drmDMA\n", | |
924 | DRM_CURRENTPID, d.send_count ); | |
925 | return DRM_ERR(EINVAL); | |
926 | } | |
927 | ||
928 | /* We'll send you buffers. | |
929 | */ | |
930 | if ( d.request_count < 0 || d.request_count > dma->buf_count ) { | |
931 | DRM_ERROR( "Process %d trying to get %d buffers (of %d max)\n", | |
932 | DRM_CURRENTPID, d.request_count, dma->buf_count ); | |
933 | return DRM_ERR(EINVAL); | |
934 | } | |
935 | ||
936 | d.granted_count = 0; | |
937 | ||
938 | if ( d.request_count ) { | |
939 | ret = r128_cce_get_buffers( filp, dev, &d ); | |
940 | } | |
941 | ||
942 | DRM_COPY_TO_USER_IOCTL(argp, d, sizeof(d) ); | |
943 | ||
944 | return ret; | |
945 | } |