1/**************************************************************************
2
3Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4All Rights Reserved.
5
6Permission is hereby granted, free of charge, to any person obtaining a
7copy of this software and associated documentation files (the
8"Software"), to deal in the Software without restriction, including
9without limitation the rights to use, copy, modify, merge, publish,
10distribute, sub license, and/or sell copies of the Software, and to
11permit persons to whom the Software is furnished to do so, subject to
12the following conditions:
13
14The above copyright notice and this permission notice (including the
15next paragraph) shall be included in all copies or substantial portions
16of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
22ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24SOFTWARE 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
45int
46I810AllocLow(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
59int
60I810AllocHigh(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
73int
74I810AllocateGARTMemory(ScrnInfoPtr pScrn)
75{
76   unsigned long size = pScrn->videoRam * 1024UL;
77   I810Ptr pI810 = I810PTR(pScrn);
78   int key;
79   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 += 0x7ffff;
136   tom &= ~0x7ffff;
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 */
244void
245I810SetTiledMemory(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
344Bool
345I810BindGARTMemory(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
380Bool
381I810UnbindGARTMemory(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
412int
413I810CheckAvailableMemory(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