gl: updated glxext.h to version 27
[mesa.git] / src / mesa / drivers / dri / intel / server / intel_dri.c
1 /**
2 * \file server/intel_dri.c
3 * \brief File to perform the device-specific initialization tasks typically
4 * done in the X server.
5 *
6 * Here they are converted to run in the client (or perhaps a standalone
7 * process), and to work with the frame buffer device rather than the X
8 * server infrastructure.
9 *
10 * Copyright (C) 2006 Dave Airlie (airlied@linux.ie)
11
12 Permission is hereby granted, free of charge, to any person obtaining a
13 copy of this software and associated documentation files (the
14 "Software"), to deal in the Software without restriction, including
15 without limitation the rights to use, copy, modify, merge, publish,
16 distribute, sub license, and/or sell copies of the Software, and to
17 permit persons to whom the Software is furnished to do so, subject to
18 the following conditions:
19
20 The above copyright notice and this permission notice (including the
21 next paragraph) shall be included in all copies or substantial portions
22 of the Software.
23
24 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
27 IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR
28 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
29 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <unistd.h>
38
39 #include "driver.h"
40 #include "drm.h"
41
42 #include "intel.h"
43 #include "i830_dri.h"
44
45 #include "memops.h"
46 #include "pciaccess.h"
47
48 static size_t drm_page_size;
49 static int nextTile = 0;
50 #define xf86DrvMsg(...) do {} while(0)
51
52 static const int pitches[] = {
53 128 * 8,
54 128 * 16,
55 128 * 32,
56 128 * 64,
57 0
58 };
59
60 static Bool I830DRIDoMappings(DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea);
61
62 static unsigned long
63 GetBestTileAlignment(unsigned long size)
64 {
65 unsigned long i;
66
67 for (i = KB(512); i < size; i <<= 1)
68 ;
69
70 if (i > MB(64))
71 i = MB(64);
72
73 return i;
74 }
75
76 static void SetFenceRegs(const DRIDriverContext *ctx, I830Rec *pI830)
77 {
78 int i;
79 unsigned char *MMIO = ctx->MMIOAddress;
80
81 for (i = 0; i < 8; i++) {
82 OUTREG(FENCE + i * 4, pI830->Fence[i]);
83 // if (I810_DEBUG & DEBUG_VERBOSE_VGA)
84 fprintf(stderr,"Fence Register : %x\n", pI830->Fence[i]);
85 }
86 }
87
88 /* Tiled memory is good... really, really good...
89 *
90 * Need to make it less likely that we miss out on this - probably
91 * need to move the frontbuffer away from the 'guarenteed' alignment
92 * of the first memory segment, or perhaps allocate a discontigous
93 * framebuffer to get more alignment 'sweet spots'.
94 */
95 static void
96 SetFence(const DRIDriverContext *ctx, I830Rec *pI830,
97 int nr, unsigned int start, unsigned int pitch,
98 unsigned int size)
99 {
100 unsigned int val;
101 unsigned int fence_mask = 0;
102 unsigned int fence_pitch;
103
104 if (nr < 0 || nr > 7) {
105 fprintf(stderr,
106 "SetFence: fence %d out of range\n",nr);
107 return;
108 }
109
110 pI830->Fence[nr] = 0;
111
112 if (IS_I9XX(pI830))
113 fence_mask = ~I915G_FENCE_START_MASK;
114 else
115 fence_mask = ~I830_FENCE_START_MASK;
116
117 if (start & fence_mask) {
118 fprintf(stderr,
119 "SetFence: %d: start (0x%08x) is not %s aligned\n",
120 nr, start, (IS_I9XX(pI830)) ? "1MB" : "512k");
121 return;
122 }
123
124 if (start % size) {
125 fprintf(stderr,
126 "SetFence: %d: start (0x%08x) is not size (%dk) aligned\n",
127 nr, start, size / 1024);
128 return;
129 }
130
131 if (pitch & 127) {
132 fprintf(stderr,
133 "SetFence: %d: pitch (%d) not a multiple of 128 bytes\n",
134 nr, pitch);
135 return;
136 }
137
138 val = (start | FENCE_X_MAJOR | FENCE_VALID);
139
140 if (IS_I9XX(pI830)) {
141 switch (size) {
142 case MB(1):
143 val |= I915G_FENCE_SIZE_1M;
144 break;
145 case MB(2):
146 val |= I915G_FENCE_SIZE_2M;
147 break;
148 case MB(4):
149 val |= I915G_FENCE_SIZE_4M;
150 break;
151 case MB(8):
152 val |= I915G_FENCE_SIZE_8M;
153 break;
154 case MB(16):
155 val |= I915G_FENCE_SIZE_16M;
156 break;
157 case MB(32):
158 val |= I915G_FENCE_SIZE_32M;
159 break;
160 case MB(64):
161 val |= I915G_FENCE_SIZE_64M;
162 break;
163 default:
164 fprintf(stderr,
165 "SetFence: %d: illegal size (%d kByte)\n", nr, size / 1024);
166 return;
167 }
168 } else {
169 switch (size) {
170 case KB(512):
171 val |= FENCE_SIZE_512K;
172 break;
173 case MB(1):
174 val |= FENCE_SIZE_1M;
175 break;
176 case MB(2):
177 val |= FENCE_SIZE_2M;
178 break;
179 case MB(4):
180 val |= FENCE_SIZE_4M;
181 break;
182 case MB(8):
183 val |= FENCE_SIZE_8M;
184 break;
185 case MB(16):
186 val |= FENCE_SIZE_16M;
187 break;
188 case MB(32):
189 val |= FENCE_SIZE_32M;
190 break;
191 case MB(64):
192 val |= FENCE_SIZE_64M;
193 break;
194 default:
195 fprintf(stderr,
196 "SetFence: %d: illegal size (%d kByte)\n", nr, size / 1024);
197 return;
198 }
199 }
200
201 if (IS_I9XX(pI830))
202 fence_pitch = pitch / 512;
203 else
204 fence_pitch = pitch / 128;
205
206 switch (fence_pitch) {
207 case 1:
208 val |= FENCE_PITCH_1;
209 break;
210 case 2:
211 val |= FENCE_PITCH_2;
212 break;
213 case 4:
214 val |= FENCE_PITCH_4;
215 break;
216 case 8:
217 val |= FENCE_PITCH_8;
218 break;
219 case 16:
220 val |= FENCE_PITCH_16;
221 break;
222 case 32:
223 val |= FENCE_PITCH_32;
224 break;
225 case 64:
226 val |= FENCE_PITCH_64;
227 break;
228 default:
229 fprintf(stderr,
230 "SetFence: %d: illegal pitch (%d)\n", nr, pitch);
231 return;
232 }
233
234 pI830->Fence[nr] = val;
235 }
236
237 static Bool
238 MakeTiles(const DRIDriverContext *ctx, I830Rec *pI830, I830MemRange *pMem)
239 {
240 int pitch, ntiles, i;
241
242 pitch = pMem->Pitch * ctx->cpp;
243 /*
244 * Simply try to break the region up into at most four pieces of size
245 * equal to the alignment.
246 */
247 ntiles = ROUND_TO(pMem->Size, pMem->Alignment) / pMem->Alignment;
248 if (ntiles >= 4) {
249 return FALSE;
250 }
251
252 for (i = 0; i < ntiles; i++, nextTile++) {
253 SetFence(ctx, pI830, nextTile, pMem->Start + i * pMem->Alignment,
254 pitch, pMem->Alignment);
255 }
256 return TRUE;
257 }
258
259 static void I830SetupMemoryTiling(const DRIDriverContext *ctx, I830Rec *pI830)
260 {
261 int i;
262
263 /* Clear out */
264 for (i = 0; i < 8; i++)
265 pI830->Fence[i] = 0;
266
267 nextTile = 0;
268
269 if (pI830->BackBuffer.Alignment >= KB(512)) {
270 if (MakeTiles(ctx, pI830, &(pI830->BackBuffer))) {
271 fprintf(stderr,
272 "Activating tiled memory for the back buffer.\n");
273 } else {
274 fprintf(stderr,
275 "MakeTiles failed for the back buffer.\n");
276 pI830->allowPageFlip = FALSE;
277 }
278 }
279
280 if (pI830->DepthBuffer.Alignment >= KB(512)) {
281 if (MakeTiles(ctx, pI830, &(pI830->DepthBuffer))) {
282 fprintf(stderr,
283 "Activating tiled memory for the depth buffer.\n");
284 } else {
285 fprintf(stderr,
286 "MakeTiles failed for the depth buffer.\n");
287 }
288 }
289
290 return;
291 }
292
293 static int I830DetectMemory(const DRIDriverContext *ctx, I830Rec *pI830)
294 {
295 struct pci_device host_bridge, ig_dev;
296 uint32_t gmch_ctrl;
297 int memsize = 0;
298 int range;
299 uint32_t aper_size;
300 uint32_t membase2 = 0;
301
302 memset(&host_bridge, 0, sizeof(host_bridge));
303 memset(&ig_dev, 0, sizeof(ig_dev));
304
305 ig_dev.dev = 2;
306
307 pci_device_cfg_read_u32(&host_bridge, &gmch_ctrl, I830_GMCH_CTRL);
308
309 if (IS_I830(pI830) || IS_845G(pI830)) {
310 if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
311 aper_size = 0x80000000;
312 } else {
313 aper_size = 0x40000000;
314 }
315 } else {
316 if (IS_I9XX(pI830)) {
317 int ret;
318 ret = pci_device_cfg_read_u32(&ig_dev, &membase2, 0x18);
319 if (membase2 & 0x08000000)
320 aper_size = 0x8000000;
321 else
322 aper_size = 0x10000000;
323
324 fprintf(stderr,"aper size is %08X %08x %d\n", aper_size, membase2, ret);
325 } else
326 aper_size = 0x8000000;
327 }
328
329 pI830->aper_size = aper_size;
330
331
332 /* We need to reduce the stolen size, by the GTT and the popup.
333 * The GTT varying according the the FbMapSize and the popup is 4KB */
334 range = (ctx->shared.fbSize / (1024*1024)) + 4;
335
336 if (IS_I85X(pI830) || IS_I865G(pI830) || IS_I9XX(pI830)) {
337 switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
338 case I855_GMCH_GMS_STOLEN_1M:
339 memsize = MB(1) - KB(range);
340 break;
341 case I855_GMCH_GMS_STOLEN_4M:
342 memsize = MB(4) - KB(range);
343 break;
344 case I855_GMCH_GMS_STOLEN_8M:
345 memsize = MB(8) - KB(range);
346 break;
347 case I855_GMCH_GMS_STOLEN_16M:
348 memsize = MB(16) - KB(range);
349 break;
350 case I855_GMCH_GMS_STOLEN_32M:
351 memsize = MB(32) - KB(range);
352 break;
353 case I915G_GMCH_GMS_STOLEN_48M:
354 if (IS_I9XX(pI830))
355 memsize = MB(48) - KB(range);
356 break;
357 case I915G_GMCH_GMS_STOLEN_64M:
358 if (IS_I9XX(pI830))
359 memsize = MB(64) - KB(range);
360 break;
361 }
362 } else {
363 switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
364 case I830_GMCH_GMS_STOLEN_512:
365 memsize = KB(512) - KB(range);
366 break;
367 case I830_GMCH_GMS_STOLEN_1024:
368 memsize = MB(1) - KB(range);
369 break;
370 case I830_GMCH_GMS_STOLEN_8192:
371 memsize = MB(8) - KB(range);
372 break;
373 case I830_GMCH_GMS_LOCAL:
374 memsize = 0;
375 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
376 "Local memory found, but won't be used.\n");
377 break;
378 }
379 }
380 if (memsize > 0) {
381 fprintf(stderr,
382 "detected %d kB stolen memory.\n", memsize / 1024);
383 } else {
384 fprintf(stderr,
385 "no video memory detected.\n");
386 }
387 return memsize;
388 }
389
390 static int AgpInit(const DRIDriverContext *ctx, I830Rec *info)
391 {
392 unsigned long mode = 0x4;
393
394 if (drmAgpAcquire(ctx->drmFD) < 0) {
395 fprintf(stderr, "[gart] AGP not available\n");
396 return 0;
397 }
398
399 if (drmAgpEnable(ctx->drmFD, mode) < 0) {
400 fprintf(stderr, "[gart] AGP not enabled\n");
401 drmAgpRelease(ctx->drmFD);
402 return 0;
403 }
404 else
405 fprintf(stderr, "[gart] AGP enabled at %dx\n", ctx->agpmode);
406
407 return 1;
408 }
409
410 /*
411 * Allocate memory from the given pool. Grow the pool if needed and if
412 * possible.
413 */
414 static unsigned long
415 AllocFromPool(const DRIDriverContext *ctx, I830Rec *pI830,
416 I830MemRange *result, I830MemPool *pool,
417 long size, unsigned long alignment, int flags)
418 {
419 long needed, start, end;
420
421 if (!result || !pool || !size)
422 return 0;
423
424 /* Calculate how much space is needed. */
425 if (alignment <= GTT_PAGE_SIZE)
426 needed = size;
427 else {
428 start = ROUND_TO(pool->Free.Start, alignment);
429 end = ROUND_TO(start + size, alignment);
430 needed = end - pool->Free.Start;
431 }
432 if (needed > pool->Free.Size) {
433 return 0;
434 }
435
436 result->Start = ROUND_TO(pool->Free.Start, alignment);
437 pool->Free.Start += needed;
438 result->End = pool->Free.Start;
439
440 pool->Free.Size = pool->Free.End - pool->Free.Start;
441 result->Size = result->End - result->Start;
442 result->Pool = pool;
443 result->Alignment = alignment;
444 return needed;
445 }
446
447 static unsigned long AllocFromAGP(const DRIDriverContext *ctx, I830Rec *pI830, long size, unsigned long alignment, I830MemRange *result)
448 {
449 unsigned long start, end;
450 unsigned long newApStart, newApEnd;
451 int ret;
452 if (!result || !size)
453 return 0;
454
455 if (!alignment)
456 alignment = 4;
457
458 start = ROUND_TO(pI830->MemoryAperture.Start, alignment);
459 end = ROUND_TO(start + size, alignment);
460 newApStart = end;
461 newApEnd = pI830->MemoryAperture.End;
462
463 ret=drmAgpAlloc(ctx->drmFD, size, 0, &(result->Physical), (drm_handle_t *)&(result->Key));
464
465 if (ret)
466 {
467 fprintf(stderr,"drmAgpAlloc failed %d\n", ret);
468 return 0;
469 }
470 pI830->allocatedMemory += size;
471 pI830->MemoryAperture.Start = newApStart;
472 pI830->MemoryAperture.End = newApEnd;
473 pI830->MemoryAperture.Size = newApEnd - newApStart;
474 // pI830->FreeMemory -= size;
475 result->Start = start;
476 result->End = start + size;
477 result->Size = size;
478 result->Offset = start;
479 result->Alignment = alignment;
480 result->Pool = NULL;
481
482 return size;
483 }
484
485 unsigned long
486 I830AllocVidMem(const DRIDriverContext *ctx, I830Rec *pI830,
487 I830MemRange *result, I830MemPool *pool, long size,
488 unsigned long alignment, int flags)
489 {
490 unsigned long ret;
491
492 if (!result)
493 return 0;
494
495 /* Make sure these are initialised. */
496 result->Size = 0;
497 result->Key = -1;
498
499 if (!size) {
500 return 0;
501 }
502
503 if (pool->Free.Size < size) {
504 ret = AllocFromAGP(ctx, pI830, size, alignment, result);
505 }
506 else {
507 ret = AllocFromPool(ctx, pI830, result, pool, size, alignment, flags);
508 if (ret == 0)
509 ret = AllocFromAGP(ctx, pI830, size, alignment, result);
510 }
511 return ret;
512 }
513
514 static Bool BindAgpRange(const DRIDriverContext *ctx, I830MemRange *mem)
515 {
516 if (!mem)
517 return FALSE;
518
519 if (mem->Key == -1)
520 return TRUE;
521
522 return !drmAgpBind(ctx->drmFD, mem->Key, mem->Offset);
523 }
524
525 /* simple memory allocation routines needed */
526 /* put ring buffer in low memory */
527 /* need to allocate front, back, depth buffers aligned correctly,
528 allocate ring buffer,
529 */
530
531 /* */
532 static Bool
533 I830AllocateMemory(const DRIDriverContext *ctx, I830Rec *pI830)
534 {
535 unsigned long size, ret;
536 unsigned long lines, lineSize, align;
537
538 /* allocate ring buffer */
539 memset(pI830->LpRing, 0, sizeof(I830RingBuffer));
540 pI830->LpRing->mem.Key = -1;
541
542 size = PRIMARY_RINGBUFFER_SIZE;
543
544 ret = I830AllocVidMem(ctx, pI830, &pI830->LpRing->mem, &pI830->StolenPool, size, 0x1000, 0);
545
546 if (ret != size)
547 {
548 fprintf(stderr,"unable to allocate ring buffer %ld\n", ret);
549 return FALSE;
550 }
551
552 pI830->LpRing->tail_mask = pI830->LpRing->mem.Size - 1;
553
554
555 /* allocate front buffer */
556 memset(&(pI830->FrontBuffer), 0, sizeof(pI830->FrontBuffer));
557 pI830->FrontBuffer.Key = -1;
558 pI830->FrontBuffer.Pitch = ctx->shared.virtualWidth;
559
560 align = KB(512);
561
562 lineSize = ctx->shared.virtualWidth * ctx->cpp;
563 lines = (ctx->shared.virtualHeight + 15) / 16 * 16;
564 size = lineSize * lines;
565 size = ROUND_TO_PAGE(size);
566
567 align = GetBestTileAlignment(size);
568
569 ret = I830AllocVidMem(ctx, pI830, &pI830->FrontBuffer, &pI830->StolenPool, size, align, 0);
570 if (ret < size)
571 {
572 fprintf(stderr,"unable to allocate front buffer %ld\n", ret);
573 return FALSE;
574 }
575
576 memset(&(pI830->BackBuffer), 0, sizeof(pI830->BackBuffer));
577 pI830->BackBuffer.Key = -1;
578 pI830->BackBuffer.Pitch = ctx->shared.virtualWidth;
579
580 ret = I830AllocVidMem(ctx, pI830, &pI830->BackBuffer, &pI830->StolenPool, size, align, 0);
581 if (ret < size)
582 {
583 fprintf(stderr,"unable to allocate back buffer %ld\n", ret);
584 return FALSE;
585 }
586
587 memset(&(pI830->DepthBuffer), 0, sizeof(pI830->DepthBuffer));
588 pI830->DepthBuffer.Key = -1;
589 pI830->DepthBuffer.Pitch = ctx->shared.virtualWidth;
590
591 ret = I830AllocVidMem(ctx, pI830, &pI830->DepthBuffer, &pI830->StolenPool, size, align, 0);
592 if (ret < size)
593 {
594 fprintf(stderr,"unable to allocate depth buffer %ld\n", ret);
595 return FALSE;
596 }
597
598 memset(&(pI830->ContextMem), 0, sizeof(pI830->ContextMem));
599 pI830->ContextMem.Key = -1;
600 size = KB(32);
601
602 ret = I830AllocVidMem(ctx, pI830, &pI830->ContextMem, &pI830->StolenPool, size, align, 0);
603 if (ret < size)
604 {
605 fprintf(stderr,"unable to allocate context buffer %ld\n", ret);
606 return FALSE;
607 }
608
609 #if 0
610 memset(&(pI830->TexMem), 0, sizeof(pI830->TexMem));
611 pI830->TexMem.Key = -1;
612
613 size = 32768 * 1024;
614 ret = AllocFromAGP(ctx, pI830, size, align, &pI830->TexMem);
615 if (ret < size)
616 {
617 fprintf(stderr,"unable to allocate texture memory %ld\n", ret);
618 return FALSE;
619 }
620 #endif
621
622 return TRUE;
623 }
624
625 static Bool
626 I830BindMemory(const DRIDriverContext *ctx, I830Rec *pI830)
627 {
628 if (!BindAgpRange(ctx, &pI830->LpRing->mem))
629 return FALSE;
630 if (!BindAgpRange(ctx, &pI830->FrontBuffer))
631 return FALSE;
632 if (!BindAgpRange(ctx, &pI830->BackBuffer))
633 return FALSE;
634 if (!BindAgpRange(ctx, &pI830->DepthBuffer))
635 return FALSE;
636 if (!BindAgpRange(ctx, &pI830->ContextMem))
637 return FALSE;
638 #if 0
639 if (!BindAgpRange(ctx, &pI830->TexMem))
640 return FALSE;
641 #endif
642 return TRUE;
643 }
644
645 static void SetupDRIMM(const DRIDriverContext *ctx, I830Rec *pI830)
646 {
647 unsigned long aperEnd = ROUND_DOWN_TO(pI830->aper_size, GTT_PAGE_SIZE) / GTT_PAGE_SIZE;
648 unsigned long aperStart = ROUND_TO(pI830->aper_size - KB(32768), GTT_PAGE_SIZE) / GTT_PAGE_SIZE;
649
650 fprintf(stderr, "aper size is %08X\n", ctx->shared.fbSize);
651 if (drmMMInit(ctx->drmFD, aperStart, aperEnd - aperStart, DRM_BO_MEM_TT)) {
652 fprintf(stderr,
653 "DRM MM Initialization Failed\n");
654 } else {
655 fprintf(stderr,
656 "DRM MM Initialized at offset 0x%lx length %d page\n", aperStart, aperEnd-aperStart);
657 }
658
659 }
660
661 static Bool
662 I830CleanupDma(const DRIDriverContext *ctx)
663 {
664 drmI830Init info;
665
666 memset(&info, 0, sizeof(drmI830Init));
667 info.func = I830_CLEANUP_DMA;
668
669 if (drmCommandWrite(ctx->drmFD, DRM_I830_INIT,
670 &info, sizeof(drmI830Init))) {
671 fprintf(stderr, "I830 Dma Cleanup Failed\n");
672 return FALSE;
673 }
674
675 return TRUE;
676 }
677
678 static Bool
679 I830InitDma(const DRIDriverContext *ctx, I830Rec *pI830)
680 {
681 I830RingBuffer *ring = pI830->LpRing;
682 drmI830Init info;
683
684 memset(&info, 0, sizeof(drmI830Init));
685 info.func = I830_INIT_DMA;
686
687 info.ring_start = ring->mem.Start + pI830->LinearAddr;
688 info.ring_end = ring->mem.End + pI830->LinearAddr;
689 info.ring_size = ring->mem.Size;
690
691 info.mmio_offset = (unsigned int)ctx->MMIOStart;
692
693 info.sarea_priv_offset = sizeof(drm_sarea_t);
694
695 info.front_offset = pI830->FrontBuffer.Start;
696 info.back_offset = pI830->BackBuffer.Start;
697 info.depth_offset = pI830->DepthBuffer.Start;
698 info.w = ctx->shared.virtualWidth;
699 info.h = ctx->shared.virtualHeight;
700 info.pitch = ctx->shared.virtualWidth;
701 info.back_pitch = pI830->BackBuffer.Pitch;
702 info.depth_pitch = pI830->DepthBuffer.Pitch;
703 info.cpp = ctx->cpp;
704
705 if (drmCommandWrite(ctx->drmFD, DRM_I830_INIT,
706 &info, sizeof(drmI830Init))) {
707 fprintf(stderr,
708 "I830 Dma Initialization Failed\n");
709 return FALSE;
710 }
711
712 return TRUE;
713 }
714
715 static int I830CheckDRMVersion( const DRIDriverContext *ctx,
716 I830Rec *pI830 )
717 {
718 drmVersionPtr version;
719
720 version = drmGetVersion(ctx->drmFD);
721
722 if (version) {
723 int req_minor, req_patch;
724
725 req_minor = 4;
726 req_patch = 0;
727
728 if (version->version_major != 1 ||
729 version->version_minor < req_minor ||
730 (version->version_minor == req_minor &&
731 version->version_patchlevel < req_patch)) {
732 /* Incompatible drm version */
733 fprintf(stderr,
734 "[dri] I830DRIScreenInit failed because of a version "
735 "mismatch.\n"
736 "[dri] i915.o kernel module version is %d.%d.%d "
737 "but version 1.%d.%d or newer is needed.\n"
738 "[dri] Disabling DRI.\n",
739 version->version_major,
740 version->version_minor,
741 version->version_patchlevel,
742 req_minor,
743 req_patch);
744 drmFreeVersion(version);
745 return 0;
746 }
747
748 pI830->drmMinor = version->version_minor;
749 drmFreeVersion(version);
750 }
751 return 1;
752 }
753
754 static void
755 I830SetRingRegs(const DRIDriverContext *ctx, I830Rec *pI830)
756 {
757 unsigned int itemp;
758 unsigned char *MMIO = ctx->MMIOAddress;
759
760 OUTREG(LP_RING + RING_LEN, 0);
761 OUTREG(LP_RING + RING_TAIL, 0);
762 OUTREG(LP_RING + RING_HEAD, 0);
763
764 if ((long)(pI830->LpRing->mem.Start & I830_RING_START_MASK) !=
765 pI830->LpRing->mem.Start) {
766 fprintf(stderr,
767 "I830SetRingRegs: Ring buffer start (%lx) violates its "
768 "mask (%x)\n", pI830->LpRing->mem.Start, I830_RING_START_MASK);
769 }
770 /* Don't care about the old value. Reserved bits must be zero anyway. */
771 itemp = pI830->LpRing->mem.Start & I830_RING_START_MASK;
772 OUTREG(LP_RING + RING_START, itemp);
773
774 if (((pI830->LpRing->mem.Size - 4096) & I830_RING_NR_PAGES) !=
775 pI830->LpRing->mem.Size - 4096) {
776 fprintf(stderr,
777 "I830SetRingRegs: Ring buffer size - 4096 (%lx) violates its "
778 "mask (%x)\n", pI830->LpRing->mem.Size - 4096,
779 I830_RING_NR_PAGES);
780 }
781 /* Don't care about the old value. Reserved bits must be zero anyway. */
782 itemp = (pI830->LpRing->mem.Size - 4096) & I830_RING_NR_PAGES;
783 itemp |= (RING_NO_REPORT | RING_VALID);
784 OUTREG(LP_RING + RING_LEN, itemp);
785
786 pI830->LpRing->head = INREG(LP_RING + RING_HEAD) & I830_HEAD_MASK;
787 pI830->LpRing->tail = INREG(LP_RING + RING_TAIL);
788 pI830->LpRing->space = pI830->LpRing->head - (pI830->LpRing->tail + 8);
789 if (pI830->LpRing->space < 0)
790 pI830->LpRing->space += pI830->LpRing->mem.Size;
791
792 SetFenceRegs(ctx, pI830);
793
794 /* RESET THE DISPLAY PIPE TO POINT TO THE FRONTBUFFER - hacky
795 hacky hacky */
796 OUTREG(DSPABASE, pI830->FrontBuffer.Start + pI830->LinearAddr);
797
798 }
799
800 static Bool
801 I830SetParam(const DRIDriverContext *ctx, int param, int value)
802 {
803 drmI830SetParam sp;
804
805 memset(&sp, 0, sizeof(sp));
806 sp.param = param;
807 sp.value = value;
808
809 if (drmCommandWrite(ctx->drmFD, DRM_I830_SETPARAM, &sp, sizeof(sp))) {
810 fprintf(stderr, "I830 SetParam Failed\n");
811 return FALSE;
812 }
813
814 return TRUE;
815 }
816
817 static Bool
818 I830DRIMapScreenRegions(DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea)
819 {
820 fprintf(stderr,
821 "[drm] Mapping front buffer\n");
822
823 if (drmAddMap(ctx->drmFD,
824 (drm_handle_t)(sarea->front_offset + pI830->LinearAddr),
825 sarea->front_size,
826 DRM_FRAME_BUFFER, /*DRM_AGP,*/
827 0,
828 &sarea->front_handle) < 0) {
829 fprintf(stderr,
830 "[drm] drmAddMap(front_handle) failed. Disabling DRI\n");
831 return FALSE;
832 }
833 ctx->shared.hFrameBuffer = sarea->front_handle;
834 ctx->shared.fbSize = sarea->front_size;
835 fprintf(stderr, "[drm] Front Buffer = 0x%08x\n",
836 sarea->front_handle);
837
838 if (drmAddMap(ctx->drmFD,
839 (drm_handle_t)(sarea->back_offset),
840 sarea->back_size, DRM_AGP, 0,
841 &sarea->back_handle) < 0) {
842 fprintf(stderr,
843 "[drm] drmAddMap(back_handle) failed. Disabling DRI\n");
844 return FALSE;
845 }
846 fprintf(stderr, "[drm] Back Buffer = 0x%08x\n",
847 sarea->back_handle);
848
849 if (drmAddMap(ctx->drmFD,
850 (drm_handle_t)sarea->depth_offset,
851 sarea->depth_size, DRM_AGP, 0,
852 &sarea->depth_handle) < 0) {
853 fprintf(stderr,
854 "[drm] drmAddMap(depth_handle) failed. Disabling DRI\n");
855 return FALSE;
856 }
857 fprintf(stderr, "[drm] Depth Buffer = 0x%08x\n",
858 sarea->depth_handle);
859
860 #if 0
861 if (drmAddMap(ctx->drmFD,
862 (drm_handle_t)sarea->tex_offset,
863 sarea->tex_size, DRM_AGP, 0,
864 &sarea->tex_handle) < 0) {
865 fprintf(stderr,
866 "[drm] drmAddMap(tex_handle) failed. Disabling DRI\n");
867 return FALSE;
868 }
869 fprintf(stderr, "[drm] textures = 0x%08x\n",
870 sarea->tex_handle);
871 #endif
872 return TRUE;
873 }
874
875
876 static void
877 I830DRIUnmapScreenRegions(const DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea)
878 {
879 #if 1
880 if (sarea->front_handle) {
881 drmRmMap(ctx->drmFD, sarea->front_handle);
882 sarea->front_handle = 0;
883 }
884 #endif
885 if (sarea->back_handle) {
886 drmRmMap(ctx->drmFD, sarea->back_handle);
887 sarea->back_handle = 0;
888 }
889 if (sarea->depth_handle) {
890 drmRmMap(ctx->drmFD, sarea->depth_handle);
891 sarea->depth_handle = 0;
892 }
893 if (sarea->tex_handle) {
894 drmRmMap(ctx->drmFD, sarea->tex_handle);
895 sarea->tex_handle = 0;
896 }
897 }
898
899 static Bool
900 I830DRIDoMappings(DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea)
901 {
902 if (drmAddMap(ctx->drmFD,
903 (drm_handle_t)pI830->LpRing->mem.Start,
904 pI830->LpRing->mem.Size, DRM_AGP, 0,
905 &pI830->ring_map) < 0) {
906 fprintf(stderr,
907 "[drm] drmAddMap(ring_map) failed. Disabling DRI\n");
908 return FALSE;
909 }
910 fprintf(stderr, "[drm] ring buffer = 0x%08x\n",
911 pI830->ring_map);
912
913 if (I830InitDma(ctx, pI830) == FALSE) {
914 return FALSE;
915 }
916
917 /* init to zero to be safe */
918
919 I830DRIMapScreenRegions(ctx, pI830, sarea);
920 SetupDRIMM(ctx, pI830);
921
922 if (ctx->pciDevice != PCI_CHIP_845_G &&
923 ctx->pciDevice != PCI_CHIP_I830_M) {
924 I830SetParam(ctx, I830_SETPARAM_USE_MI_BATCHBUFFER_START, 1 );
925 }
926
927 /* Okay now initialize the dma engine */
928 {
929 pI830->irq = drmGetInterruptFromBusID(ctx->drmFD,
930 ctx->pciBus,
931 ctx->pciDevice,
932 ctx->pciFunc);
933
934 if (drmCtlInstHandler(ctx->drmFD, pI830->irq)) {
935 fprintf(stderr,
936 "[drm] failure adding irq handler\n");
937 pI830->irq = 0;
938 return FALSE;
939 }
940 else
941 fprintf(stderr,
942 "[drm] dma control initialized, using IRQ %d\n",
943 pI830->irq);
944 }
945
946 fprintf(stderr, "[dri] visual configs initialized\n");
947
948 return TRUE;
949 }
950
951 static Bool
952 I830ClearScreen(DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea)
953 {
954 /* need to drmMap front and back buffers and zero them */
955 drmAddress map_addr;
956 int ret;
957
958 ret = drmMap(ctx->drmFD,
959 sarea->front_handle,
960 sarea->front_size,
961 &map_addr);
962
963 if (ret)
964 {
965 fprintf(stderr, "Unable to map front buffer\n");
966 return FALSE;
967 }
968
969 drimemsetio((char *)map_addr,
970 0,
971 sarea->front_size);
972 drmUnmap(map_addr, sarea->front_size);
973
974
975 ret = drmMap(ctx->drmFD,
976 sarea->back_handle,
977 sarea->back_size,
978 &map_addr);
979
980 if (ret)
981 {
982 fprintf(stderr, "Unable to map back buffer\n");
983 return FALSE;
984 }
985
986 drimemsetio((char *)map_addr,
987 0,
988 sarea->back_size);
989 drmUnmap(map_addr, sarea->back_size);
990
991 return TRUE;
992 }
993
994 static Bool
995 I830ScreenInit(DRIDriverContext *ctx, I830Rec *pI830)
996
997 {
998 I830DRIPtr pI830DRI;
999 drmI830Sarea *pSAREAPriv;
1000 int err;
1001
1002 drm_page_size = getpagesize();
1003
1004 pI830->registerSize = ctx->MMIOSize;
1005 /* This is a hack for now. We have to have more than a 4k page here
1006 * because of the size of the state. However, the state should be
1007 * in a per-context mapping. This will be added in the Mesa 3.5 port
1008 * of the I830 driver.
1009 */
1010 ctx->shared.SAREASize = SAREA_MAX;
1011
1012 /* Note that drmOpen will try to load the kernel module, if needed. */
1013 ctx->drmFD = drmOpen("i915", NULL );
1014 if (ctx->drmFD < 0) {
1015 fprintf(stderr, "[drm] drmOpen failed\n");
1016 return 0;
1017 }
1018
1019 if ((err = drmSetBusid(ctx->drmFD, ctx->pciBusID)) < 0) {
1020 fprintf(stderr, "[drm] drmSetBusid failed (%d, %s), %s\n",
1021 ctx->drmFD, ctx->pciBusID, strerror(-err));
1022 return 0;
1023 }
1024
1025 if (drmAddMap( ctx->drmFD,
1026 0,
1027 ctx->shared.SAREASize,
1028 DRM_SHM,
1029 DRM_CONTAINS_LOCK,
1030 &ctx->shared.hSAREA) < 0)
1031 {
1032 fprintf(stderr, "[drm] drmAddMap failed\n");
1033 return 0;
1034 }
1035
1036 fprintf(stderr, "[drm] added %d byte SAREA at 0x%08x\n",
1037 ctx->shared.SAREASize, ctx->shared.hSAREA);
1038
1039 if (drmMap( ctx->drmFD,
1040 ctx->shared.hSAREA,
1041 ctx->shared.SAREASize,
1042 (drmAddressPtr)(&ctx->pSAREA)) < 0)
1043 {
1044 fprintf(stderr, "[drm] drmMap failed\n");
1045 return 0;
1046
1047 }
1048
1049 memset(ctx->pSAREA, 0, ctx->shared.SAREASize);
1050 fprintf(stderr, "[drm] mapped SAREA 0x%08x to %p, size %d\n",
1051 ctx->shared.hSAREA, ctx->pSAREA, ctx->shared.SAREASize);
1052
1053
1054 if (drmAddMap(ctx->drmFD,
1055 ctx->MMIOStart,
1056 ctx->MMIOSize,
1057 DRM_REGISTERS,
1058 DRM_READ_ONLY,
1059 &pI830->registerHandle) < 0) {
1060 fprintf(stderr, "[drm] drmAddMap mmio failed\n");
1061 return 0;
1062 }
1063 fprintf(stderr,
1064 "[drm] register handle = 0x%08x\n", pI830->registerHandle);
1065
1066
1067 if (!I830CheckDRMVersion(ctx, pI830)) {
1068 return FALSE;
1069 }
1070
1071 /* Create a 'server' context so we can grab the lock for
1072 * initialization ioctls.
1073 */
1074 if ((err = drmCreateContext(ctx->drmFD, &ctx->serverContext)) != 0) {
1075 fprintf(stderr, "%s: drmCreateContext failed %d\n", __FUNCTION__, err);
1076 return 0;
1077 }
1078
1079 DRM_LOCK(ctx->drmFD, ctx->pSAREA, ctx->serverContext, 0);
1080
1081 /* Initialize the SAREA private data structure */
1082 pSAREAPriv = (drmI830Sarea *)(((char*)ctx->pSAREA) +
1083 sizeof(drm_sarea_t));
1084 memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
1085
1086 pI830->StolenMemory.Size = I830DetectMemory(ctx, pI830);
1087 pI830->StolenMemory.Start = 0;
1088 pI830->StolenMemory.End = pI830->StolenMemory.Size;
1089
1090 pI830->MemoryAperture.Start = pI830->StolenMemory.End;
1091 pI830->MemoryAperture.End = KB(40000);
1092 pI830->MemoryAperture.Size = pI830->MemoryAperture.End - pI830->MemoryAperture.Start;
1093
1094 pI830->StolenPool.Fixed = pI830->StolenMemory;
1095 pI830->StolenPool.Total = pI830->StolenMemory;
1096 pI830->StolenPool.Free = pI830->StolenPool.Total;
1097 pI830->FreeMemory = pI830->StolenPool.Total.Size;
1098
1099 if (!AgpInit(ctx, pI830))
1100 return FALSE;
1101
1102 if (I830AllocateMemory(ctx, pI830) == FALSE)
1103 {
1104 return FALSE;
1105 }
1106
1107 if (I830BindMemory(ctx, pI830) == FALSE)
1108 {
1109 return FALSE;
1110 }
1111
1112 pSAREAPriv->rotated_offset = -1;
1113 pSAREAPriv->rotated_size = 0;
1114 pSAREAPriv->rotated_pitch = ctx->shared.virtualWidth;
1115
1116 pSAREAPriv->front_offset = pI830->FrontBuffer.Start;
1117 pSAREAPriv->front_size = pI830->FrontBuffer.Size;
1118 pSAREAPriv->width = ctx->shared.virtualWidth;
1119 pSAREAPriv->height = ctx->shared.virtualHeight;
1120 pSAREAPriv->pitch = ctx->shared.virtualWidth;
1121 pSAREAPriv->virtualX = ctx->shared.virtualWidth;
1122 pSAREAPriv->virtualY = ctx->shared.virtualHeight;
1123 pSAREAPriv->back_offset = pI830->BackBuffer.Start;
1124 pSAREAPriv->back_size = pI830->BackBuffer.Size;
1125 pSAREAPriv->depth_offset = pI830->DepthBuffer.Start;
1126 pSAREAPriv->depth_size = pI830->DepthBuffer.Size;
1127 #if 0
1128 pSAREAPriv->tex_offset = pI830->TexMem.Start;
1129 pSAREAPriv->tex_size = pI830->TexMem.Size;
1130 #endif
1131 pSAREAPriv->log_tex_granularity = pI830->TexGranularity;
1132
1133 ctx->driverClientMsg = malloc(sizeof(I830DRIRec));
1134 ctx->driverClientMsgSize = sizeof(I830DRIRec);
1135 pI830DRI = (I830DRIPtr)ctx->driverClientMsg;
1136 pI830DRI->deviceID = pI830->Chipset;
1137 pI830DRI->regsSize = I830_REG_SIZE;
1138 pI830DRI->width = ctx->shared.virtualWidth;
1139 pI830DRI->height = ctx->shared.virtualHeight;
1140 pI830DRI->mem = ctx->shared.fbSize;
1141 pI830DRI->cpp = ctx->cpp;
1142
1143 pI830DRI->bitsPerPixel = ctx->bpp;
1144 pI830DRI->sarea_priv_offset = sizeof(drm_sarea_t);
1145
1146 err = I830DRIDoMappings(ctx, pI830, pSAREAPriv);
1147 if (err == FALSE)
1148 return FALSE;
1149
1150 I830SetupMemoryTiling(ctx, pI830);
1151
1152 /* Quick hack to clear the front & back buffers. Could also use
1153 * the clear ioctl to do this, but would need to setup hw state
1154 * first.
1155 */
1156 I830ClearScreen(ctx, pI830, pSAREAPriv);
1157
1158 I830SetRingRegs(ctx, pI830);
1159
1160 return TRUE;
1161 }
1162
1163
1164 /**
1165 * \brief Validate the fbdev mode.
1166 *
1167 * \param ctx display handle.
1168 *
1169 * \return one on success, or zero on failure.
1170 *
1171 * Saves some registers and returns 1.
1172 *
1173 * \sa radeonValidateMode().
1174 */
1175 static int i830ValidateMode( const DRIDriverContext *ctx )
1176 {
1177 return 1;
1178 }
1179
1180 /**
1181 * \brief Examine mode returned by fbdev.
1182 *
1183 * \param ctx display handle.
1184 *
1185 * \return one on success, or zero on failure.
1186 *
1187 * Restores registers that fbdev has clobbered and returns 1.
1188 *
1189 * \sa i810ValidateMode().
1190 */
1191 static int i830PostValidateMode( const DRIDriverContext *ctx )
1192 {
1193 I830Rec *pI830 = ctx->driverPrivate;
1194
1195 I830SetRingRegs(ctx, pI830);
1196 return 1;
1197 }
1198
1199
1200 /**
1201 * \brief Initialize the framebuffer device mode
1202 *
1203 * \param ctx display handle.
1204 *
1205 * \return one on success, or zero on failure.
1206 *
1207 * Fills in \p info with some default values and some information from \p ctx
1208 * and then calls I810ScreenInit() for the screen initialization.
1209 *
1210 * Before exiting clears the framebuffer memory accessing it directly.
1211 */
1212 static int i830InitFBDev( DRIDriverContext *ctx )
1213 {
1214 I830Rec *pI830 = calloc(1, sizeof(I830Rec));
1215 int i;
1216
1217 {
1218 int dummy = ctx->shared.virtualWidth;
1219
1220 switch (ctx->bpp / 8) {
1221 case 1: dummy = (ctx->shared.virtualWidth + 127) & ~127; break;
1222 case 2: dummy = (ctx->shared.virtualWidth + 31) & ~31; break;
1223 case 3:
1224 case 4: dummy = (ctx->shared.virtualWidth + 15) & ~15; break;
1225 }
1226
1227 ctx->shared.virtualWidth = dummy;
1228 ctx->shared.Width = ctx->shared.virtualWidth;
1229 }
1230
1231
1232 for (i = 0; pitches[i] != 0; i++) {
1233 if (pitches[i] >= ctx->shared.virtualWidth) {
1234 ctx->shared.virtualWidth = pitches[i];
1235 break;
1236 }
1237 }
1238
1239 ctx->driverPrivate = (void *)pI830;
1240
1241 pI830->LpRing = calloc(1, sizeof(I830RingBuffer));
1242 pI830->Chipset = ctx->chipset;
1243 pI830->LinearAddr = ctx->FBStart;
1244
1245 if (!I830ScreenInit( ctx, pI830 ))
1246 return 0;
1247
1248
1249 return 1;
1250 }
1251
1252
1253 /**
1254 * \brief The screen is being closed, so clean up any state and free any
1255 * resources used by the DRI.
1256 *
1257 * \param ctx display handle.
1258 *
1259 * Unmaps the SAREA, closes the DRM device file descriptor and frees the driver
1260 * private data.
1261 */
1262 static void i830HaltFBDev( DRIDriverContext *ctx )
1263 {
1264 drmI830Sarea *pSAREAPriv;
1265 I830Rec *pI830 = ctx->driverPrivate;
1266
1267 if (pI830->irq) {
1268 drmCtlUninstHandler(ctx->drmFD);
1269 pI830->irq = 0; }
1270
1271 I830CleanupDma(ctx);
1272
1273 pSAREAPriv = (drmI830Sarea *)(((char*)ctx->pSAREA) +
1274 sizeof(drm_sarea_t));
1275
1276 I830DRIUnmapScreenRegions(ctx, pI830, pSAREAPriv);
1277 drmUnmap( ctx->pSAREA, ctx->shared.SAREASize );
1278 drmClose(ctx->drmFD);
1279
1280 if (ctx->driverPrivate) {
1281 free(ctx->driverPrivate);
1282 ctx->driverPrivate = 0;
1283 }
1284 }
1285
1286
1287 extern void i810NotifyFocus( int );
1288
1289 /**
1290 * \brief Exported driver interface for Mini GLX.
1291 *
1292 * \sa DRIDriverRec.
1293 */
1294 const struct DRIDriverRec __driDriver = {
1295 i830ValidateMode,
1296 i830PostValidateMode,
1297 i830InitFBDev,
1298 i830HaltFBDev,
1299 NULL,//I830EngineShutdown,
1300 NULL, //I830EngineRestore,
1301 #ifndef _EMBEDDED
1302 0,
1303 #else
1304 i810NotifyFocus,
1305 #endif
1306 };