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