1 /**************************************************************************
2 
3 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4 All Rights Reserved.
5 
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sub license, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
13 
14 The above copyright notice and this permission notice (including the
15 next paragraph) shall be included in all copies or substantial portions
16 of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
22 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 
26 **************************************************************************/
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 /*
33  * Authors:
34  *   Keith Whitwell <keith@tungstengraphics.com>
35  *
36  */
37 
38 #include "xorg-server.h"
39 #include "xf86.h"
40 #include "xf86_OSproc.h"
41 
42 #include "i810.h"
43 #include "i810_reg.h"
44 
45 int
I810AllocLow(I810MemRange * result,I810MemRange * pool,int size)46 I810AllocLow(I810MemRange * result, I810MemRange * pool, int size)
47 {
48    if (size > (long)pool->Size)
49       return 0;
50 
51    pool->Size -= size;
52    result->Size = size;
53    result->Start = pool->Start;
54    result->End = pool->Start += size;
55 
56    return 1;
57 }
58 
59 int
I810AllocHigh(I810MemRange * result,I810MemRange * pool,int size)60 I810AllocHigh(I810MemRange * result, I810MemRange * pool, int size)
61 {
62    if (size > (long)pool->Size)
63       return 0;
64 
65    pool->Size -= size;
66    result->Size = size;
67    result->End = pool->End;
68    result->Start = pool->End -= size;
69 
70    return 1;
71 }
72 
73 int
I810AllocateGARTMemory(ScrnInfoPtr pScrn)74 I810AllocateGARTMemory(ScrnInfoPtr pScrn)
75 {
76    unsigned long size = pScrn->videoRam * 1024UL;
77    I810Ptr pI810 = I810PTR(pScrn);
78    int key;
79    unsigned long tom = 0;
80    unsigned long physical;
81 
82    if (!xf86AgpGARTSupported() || !xf86AcquireGART(pScrn->scrnIndex)) {
83       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
84 		 "AGP GART support is either not available or cannot be used.\n"
85 		 "\tMake sure your kernel has agpgart support or has the\n"
86 		 "\tagpgart module loaded.\n");
87       return FALSE;
88    }
89 
90    /* This allows the 2d only Xserver to regen */
91    pI810->agpAcquired2d = TRUE;
92 
93    /*
94     * I810/I815
95     *
96     * Treat the gart like video memory - we assume we own all that is
97     * there, so ignore EBUSY errors.  Don't try to remove it on
98     * failure, either, as other X server may be using it.
99     */
100 
101    if ((key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 0, NULL)) == -1)
102       return FALSE;
103 
104    pI810->VramOffset = 0;
105    pI810->VramKey = key;
106 
107    if (!xf86BindGARTMemory(pScrn->scrnIndex, key, 0))
108       return FALSE;
109 
110    pI810->SysMem.Start = 0;
111    pI810->SysMem.Size = size;
112    pI810->SysMem.End = size;
113    pI810->SavedSysMem = pI810->SysMem;
114 
115    tom = pI810->SysMem.End;
116 
117    pI810->DcacheMem.Start = 0;
118    pI810->DcacheMem.End = 0;
119    pI810->DcacheMem.Size = 0;
120    pI810->CursorPhysical = 0;
121    pI810->CursorARGBPhysical = 0;
122 
123    /*
124     * Dcache - half the speed of normal ram, so not really useful for
125     * a 2d server.  Don't bother reporting its presence.  This is
126     * mapped in addition to the requested amount of system ram.
127     */
128 
129    size = 1024 * 4096;
130 
131    /*
132     * Keep it 512K aligned for the sake of tiled regions.
133     */
134 
135    tom += 0x7ffffUL;
136    tom &= ~0x7ffffUL;
137 
138    if ((key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 1, NULL)) != -1) {
139       pI810->DcacheOffset = tom;
140       pI810->DcacheKey = key;
141       if (!xf86BindGARTMemory(pScrn->scrnIndex, key, tom)) {
142 	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
143 		    "Allocation of %ld bytes for DCACHE failed\n", size);
144 	 pI810->DcacheKey = -1;
145       } else {
146 	 pI810->DcacheMem.Start = tom;
147 	 pI810->DcacheMem.Size = size;
148 	 pI810->DcacheMem.End = pI810->DcacheMem.Start + pI810->DcacheMem.Size;
149 	 tom = pI810->DcacheMem.End;
150       }
151    } else {
152       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
153 		 "No physical memory available for %ld bytes of DCACHE\n",
154 		 size);
155       pI810->DcacheKey = -1;
156    }
157 
158    /*
159     * Mouse cursor -- The i810 (crazy) needs a physical address in
160     * system memory from which to upload the cursor.  We get this from
161     * the agpgart module using a special memory type.
162     */
163 
164    /*
165     * 4k for the cursor is excessive, I'm going to steal 3k for
166     * overlay registers later
167     */
168 
169    size = 4096;
170 
171    if ((key =
172 	xf86AllocateGARTMemory(pScrn->scrnIndex, size, 2, &physical)) == -1) {
173       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
174 		 "No physical memory available for HW cursor\n");
175       pI810->HwcursKey = -1;
176       pI810->CursorStart = 0;
177    } else {
178       pI810->HwcursOffset = tom;
179       pI810->HwcursKey = key;
180       if (!xf86BindGARTMemory(pScrn->scrnIndex, key, tom)) {
181 	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
182 		    "Allocation of %ld bytes for HW cursor failed\n", size);
183 	 pI810->HwcursKey = -1;
184       } else {
185 	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
186 		    "Allocated of %ld bytes for HW cursor\n", size);
187 	 pI810->CursorPhysical = physical;
188 	 pI810->CursorStart = tom;
189 	 tom += size;
190       }
191    }
192 
193    /*
194     * 16k for the ARGB cursor
195     */
196 
197    size = 16384;
198 
199    if ((key =
200 	xf86AllocateGARTMemory(pScrn->scrnIndex, size, 2, &physical)) == -1) {
201       xf86DrvMsg(pScrn->scrnIndex, X_INFO,
202 		 "No physical memory available for ARGB HW cursor\n");
203       pI810->ARGBHwcursKey = -1;
204       pI810->CursorARGBStart = 0;
205    } else {
206       pI810->ARGBHwcursOffset = tom;
207       pI810->ARGBHwcursKey = key;
208       if (!xf86BindGARTMemory(pScrn->scrnIndex, key, tom)) {
209 	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
210 		    "Allocation of %ld bytes for ARGB HW cursor failed\n", size);
211 	 pI810->ARGBHwcursKey = -1;
212       } else {
213 	 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
214 		    "Allocated of %ld bytes for ARGB HW cursor\n", size);
215 	 pI810->CursorARGBPhysical = physical;
216 	 pI810->CursorARGBStart = tom;
217 	 tom += size;
218       }
219    }
220 
221    /*
222     * Overlay register buffer -- Just like the cursor, the i810 needs a
223     * physical address in system memory from which to upload the overlay
224     * registers.
225     */
226 
227    if (pI810->CursorStart != 0) {
228       pI810->OverlayPhysical = pI810->CursorPhysical + 1024;
229       pI810->OverlayStart = pI810->CursorStart + 1024;
230    }
231 
232    pI810->GttBound = 1;
233 
234    return TRUE;
235 }
236 
237 /* Tiled memory is good... really, really good...
238  *
239  * Need to make it less likely that we miss out on this - probably
240  * need to move the frontbuffer away from the 'guarenteed' alignment
241  * of the first memory segment, or perhaps allocate a discontigous
242  * framebuffer to get more alignment 'sweet spots'.
243  */
244 void
I810SetTiledMemory(ScrnInfoPtr pScrn,int nr,unsigned int start,unsigned int pitch,unsigned int size)245 I810SetTiledMemory(ScrnInfoPtr pScrn, int nr, unsigned int start,
246 		   unsigned int pitch, unsigned int size)
247 {
248    I810Ptr pI810 = I810PTR(pScrn);
249    I810RegPtr i810Reg = &pI810->ModeReg;
250    uint32_t val;
251    uint32_t fence_mask = 0;
252 
253    if (nr < 0 || nr > 7) {
254       xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "%s - fence %d out of range\n",
255 		 "I810SetTiledMemory", nr);
256       return;
257    }
258 
259    i810Reg->Fence[nr] = 0;
260 
261    fence_mask = ~FENCE_START_MASK;
262 
263    if (start & fence_mask) {
264       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
265 		 "%s %d: start (%x) is not 512k aligned\n",
266 		 "I810SetTiledMemory", nr, start);
267       return;
268    }
269 
270    if (start % size) {
271       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
272 		 "%s %d: start (%x) is not size (%x) aligned\n",
273 		 "I810SetTiledMemory", nr, start, size);
274       return;
275    }
276 
277    if (pitch & 127) {
278       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
279 		 "%s %d: pitch (%x) not a multiple of 128 bytes\n",
280 		 "I810SetTiledMemory", nr, pitch);
281       return;
282    }
283 
284    val = (start | FENCE_X_MAJOR | FENCE_VALID);
285 
286    switch (size) {
287    case KB(512):
288       val |= FENCE_SIZE_512K;
289       break;
290    case MB(1):
291       val |= FENCE_SIZE_1M;
292       break;
293    case MB(2):
294       val |= FENCE_SIZE_2M;
295       break;
296    case MB(4):
297       val |= FENCE_SIZE_4M;
298       break;
299    case MB(8):
300       val |= FENCE_SIZE_8M;
301       break;
302    case MB(16):
303       val |= FENCE_SIZE_16M;
304       break;
305    case MB(32):
306       val |= FENCE_SIZE_32M;
307       break;
308    default:
309       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
310 		 "%s %d: illegal size (0x%x)\n", "I810SetTiledMemory", nr,
311 		 size);
312       return;
313    }
314 
315    switch (pitch / 128) {
316    case 1:
317       val |= FENCE_PITCH_1;
318       break;
319    case 2:
320       val |= FENCE_PITCH_2;
321       break;
322    case 4:
323       val |= FENCE_PITCH_4;
324       break;
325    case 8:
326       val |= FENCE_PITCH_8;
327       break;
328    case 16:
329       val |= FENCE_PITCH_16;
330       break;
331    case 32:
332       val |= FENCE_PITCH_32;
333       break;
334    default:
335       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
336 		 "%s %d: illegal size (0x%x)\n", "I810SetTiledMemory", nr,
337 		 size);
338       return;
339    }
340 
341    i810Reg->Fence[nr] = val;
342 }
343 
344 Bool
I810BindGARTMemory(ScrnInfoPtr pScrn)345 I810BindGARTMemory(ScrnInfoPtr pScrn)
346 {
347    I810Ptr pI810 = I810PTR(pScrn);
348 
349    if (xf86AgpGARTSupported() && !pI810->directRenderingEnabled
350        && !pI810->GttBound) {
351       if (!xf86AcquireGART(pScrn->scrnIndex))
352 	 return FALSE;
353 
354       if (pI810->VramKey != -1
355 	  && !xf86BindGARTMemory(pScrn->scrnIndex, pI810->VramKey,
356 				 pI810->VramOffset))
357 	 return FALSE;
358 
359       if (pI810->DcacheKey != -1
360 	  && !xf86BindGARTMemory(pScrn->scrnIndex, pI810->DcacheKey,
361 				 pI810->DcacheOffset))
362 	 return FALSE;
363 
364       if (pI810->HwcursKey != -1
365 	  && !xf86BindGARTMemory(pScrn->scrnIndex, pI810->HwcursKey,
366 				 pI810->HwcursOffset))
367 	 return FALSE;
368 
369       if (pI810->ARGBHwcursKey != -1
370 	  && !xf86BindGARTMemory(pScrn->scrnIndex, pI810->ARGBHwcursKey,
371 				 pI810->ARGBHwcursOffset))
372 	 return FALSE;
373 
374       pI810->GttBound = 1;
375    }
376 
377    return TRUE;
378 }
379 
380 Bool
I810UnbindGARTMemory(ScrnInfoPtr pScrn)381 I810UnbindGARTMemory(ScrnInfoPtr pScrn)
382 {
383    I810Ptr pI810 = I810PTR(pScrn);
384 
385    if (xf86AgpGARTSupported() && !pI810->directRenderingEnabled
386        && pI810->GttBound) {
387       if (pI810->VramKey != -1
388 	  && !xf86UnbindGARTMemory(pScrn->scrnIndex, pI810->VramKey))
389 	 return FALSE;
390 
391       if (pI810->DcacheKey != -1
392 	  && !xf86UnbindGARTMemory(pScrn->scrnIndex, pI810->DcacheKey))
393 	 return FALSE;
394 
395       if (pI810->HwcursKey != -1
396 	  && !xf86UnbindGARTMemory(pScrn->scrnIndex, pI810->HwcursKey))
397 	 return FALSE;
398 
399       if (pI810->ARGBHwcursKey != -1
400 	  && !xf86UnbindGARTMemory(pScrn->scrnIndex, pI810->ARGBHwcursKey))
401 	 return FALSE;
402 
403       if (!xf86ReleaseGART(pScrn->scrnIndex))
404 	 return FALSE;
405 
406       pI810->GttBound = 0;
407    }
408 
409    return TRUE;
410 }
411 
412 int
I810CheckAvailableMemory(ScrnInfoPtr pScrn)413 I810CheckAvailableMemory(ScrnInfoPtr pScrn)
414 {
415    AgpInfoPtr agpinf;
416    int maxPages;
417 
418    if (!xf86AgpGARTSupported() ||
419        !xf86AcquireGART(pScrn->scrnIndex) ||
420        (agpinf = xf86GetAGPInfo(pScrn->scrnIndex)) == NULL ||
421        !xf86ReleaseGART(pScrn->scrnIndex))
422       return -1;
423 
424    maxPages = agpinf->totalPages - agpinf->usedPages;
425    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 2, "%s: %dk available\n",
426 		  "I810CheckAvailableMemory", maxPages * 4);
427 
428    return maxPages * 4;
429 }
430