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