2 * \file server/intel_dri.c
3 * \brief File to perform the device-specific initialization tasks typically
4 * done in the X server.
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.
10 * Copyright (C) 2006 Dave Airlie (airlied@linux.ie)
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:
20 The above copyright notice and this permission notice (including the
21 next paragraph) shall be included in all copies or substantial portions
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.
46 #include "pciaccess.h"
48 static size_t drm_page_size
;
49 static int nextTile
= 0;
50 #define xf86DrvMsg(...) do {} while(0)
52 static const int pitches
[] = {
60 static Bool
I830DRIDoMappings(DRIDriverContext
*ctx
, I830Rec
*pI830
, drmI830Sarea
*sarea
);
63 GetBestTileAlignment(unsigned long size
)
67 for (i
= KB(512); i
< size
; i
<<= 1)
76 static void SetFenceRegs(const DRIDriverContext
*ctx
, I830Rec
*pI830
)
79 unsigned char *MMIO
= ctx
->MMIOAddress
;
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
]);
88 /* Tiled memory is good... really, really good...
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'.
96 SetFence(const DRIDriverContext
*ctx
, I830Rec
*pI830
,
97 int nr
, unsigned int start
, unsigned int pitch
,
101 unsigned int fence_mask
= 0;
102 unsigned int fence_pitch
;
104 if (nr
< 0 || nr
> 7) {
106 "SetFence: fence %d out of range\n",nr
);
110 pI830
->Fence
[nr
] = 0;
113 fence_mask
= ~I915G_FENCE_START_MASK
;
115 fence_mask
= ~I830_FENCE_START_MASK
;
117 if (start
& fence_mask
) {
119 "SetFence: %d: start (0x%08x) is not %s aligned\n",
120 nr
, start
, (IS_I9XX(pI830
)) ? "1MB" : "512k");
126 "SetFence: %d: start (0x%08x) is not size (%dk) aligned\n",
127 nr
, start
, size
/ 1024);
133 "SetFence: %d: pitch (%d) not a multiple of 128 bytes\n",
138 val
= (start
| FENCE_X_MAJOR
| FENCE_VALID
);
140 if (IS_I9XX(pI830
)) {
143 val
|= I915G_FENCE_SIZE_1M
;
146 val
|= I915G_FENCE_SIZE_2M
;
149 val
|= I915G_FENCE_SIZE_4M
;
152 val
|= I915G_FENCE_SIZE_8M
;
155 val
|= I915G_FENCE_SIZE_16M
;
158 val
|= I915G_FENCE_SIZE_32M
;
161 val
|= I915G_FENCE_SIZE_64M
;
165 "SetFence: %d: illegal size (%d kByte)\n", nr
, size
/ 1024);
171 val
|= FENCE_SIZE_512K
;
174 val
|= FENCE_SIZE_1M
;
177 val
|= FENCE_SIZE_2M
;
180 val
|= FENCE_SIZE_4M
;
183 val
|= FENCE_SIZE_8M
;
186 val
|= FENCE_SIZE_16M
;
189 val
|= FENCE_SIZE_32M
;
192 val
|= FENCE_SIZE_64M
;
196 "SetFence: %d: illegal size (%d kByte)\n", nr
, size
/ 1024);
202 fence_pitch
= pitch
/ 512;
204 fence_pitch
= pitch
/ 128;
206 switch (fence_pitch
) {
208 val
|= FENCE_PITCH_1
;
211 val
|= FENCE_PITCH_2
;
214 val
|= FENCE_PITCH_4
;
217 val
|= FENCE_PITCH_8
;
220 val
|= FENCE_PITCH_16
;
223 val
|= FENCE_PITCH_32
;
226 val
|= FENCE_PITCH_64
;
230 "SetFence: %d: illegal pitch (%d)\n", nr
, pitch
);
234 pI830
->Fence
[nr
] = val
;
238 MakeTiles(const DRIDriverContext
*ctx
, I830Rec
*pI830
, I830MemRange
*pMem
)
240 int pitch
, ntiles
, i
;
242 pitch
= pMem
->Pitch
* ctx
->cpp
;
244 * Simply try to break the region up into at most four pieces of size
245 * equal to the alignment.
247 ntiles
= ROUND_TO(pMem
->Size
, pMem
->Alignment
) / pMem
->Alignment
;
252 for (i
= 0; i
< ntiles
; i
++, nextTile
++) {
253 SetFence(ctx
, pI830
, nextTile
, pMem
->Start
+ i
* pMem
->Alignment
,
254 pitch
, pMem
->Alignment
);
259 static void I830SetupMemoryTiling(const DRIDriverContext
*ctx
, I830Rec
*pI830
)
264 for (i
= 0; i
< 8; i
++)
269 if (pI830
->BackBuffer
.Alignment
>= KB(512)) {
270 if (MakeTiles(ctx
, pI830
, &(pI830
->BackBuffer
))) {
272 "Activating tiled memory for the back buffer.\n");
275 "MakeTiles failed for the back buffer.\n");
276 pI830
->allowPageFlip
= FALSE
;
280 if (pI830
->DepthBuffer
.Alignment
>= KB(512)) {
281 if (MakeTiles(ctx
, pI830
, &(pI830
->DepthBuffer
))) {
283 "Activating tiled memory for the depth buffer.\n");
286 "MakeTiles failed for the depth buffer.\n");
293 static int I830DetectMemory(const DRIDriverContext
*ctx
, I830Rec
*pI830
)
295 struct pci_device host_bridge
, ig_dev
;
300 uint32_t membase2
= 0;
302 memset(&host_bridge
, 0, sizeof(host_bridge
));
303 memset(&ig_dev
, 0, sizeof(ig_dev
));
307 pci_device_cfg_read_u32(&host_bridge
, &gmch_ctrl
, I830_GMCH_CTRL
);
309 if (IS_I830(pI830
) || IS_845G(pI830
)) {
310 if ((gmch_ctrl
& I830_GMCH_MEM_MASK
) == I830_GMCH_MEM_128M
) {
311 aper_size
= 0x80000000;
313 aper_size
= 0x40000000;
316 if (IS_I9XX(pI830
)) {
318 ret
= pci_device_cfg_read_u32(&ig_dev
, &membase2
, 0x18);
319 if (membase2
& 0x08000000)
320 aper_size
= 0x8000000;
322 aper_size
= 0x10000000;
324 fprintf(stderr
,"aper size is %08X %08x %d\n", aper_size
, membase2
, ret
);
326 aper_size
= 0x8000000;
329 pI830
->aper_size
= aper_size
;
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;
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
);
341 case I855_GMCH_GMS_STOLEN_4M
:
342 memsize
= MB(4) - KB(range
);
344 case I855_GMCH_GMS_STOLEN_8M
:
345 memsize
= MB(8) - KB(range
);
347 case I855_GMCH_GMS_STOLEN_16M
:
348 memsize
= MB(16) - KB(range
);
350 case I855_GMCH_GMS_STOLEN_32M
:
351 memsize
= MB(32) - KB(range
);
353 case I915G_GMCH_GMS_STOLEN_48M
:
355 memsize
= MB(48) - KB(range
);
357 case I915G_GMCH_GMS_STOLEN_64M
:
359 memsize
= MB(64) - KB(range
);
363 switch (gmch_ctrl
& I830_GMCH_GMS_MASK
) {
364 case I830_GMCH_GMS_STOLEN_512
:
365 memsize
= KB(512) - KB(range
);
367 case I830_GMCH_GMS_STOLEN_1024
:
368 memsize
= MB(1) - KB(range
);
370 case I830_GMCH_GMS_STOLEN_8192
:
371 memsize
= MB(8) - KB(range
);
373 case I830_GMCH_GMS_LOCAL
:
375 xf86DrvMsg(pScrn
->scrnIndex
, X_WARNING
,
376 "Local memory found, but won't be used.\n");
382 "detected %d kB stolen memory.\n", memsize
/ 1024);
385 "no video memory detected.\n");
390 static int AgpInit(const DRIDriverContext
*ctx
, I830Rec
*info
)
392 unsigned long mode
= 0x4;
394 if (drmAgpAcquire(ctx
->drmFD
) < 0) {
395 fprintf(stderr
, "[gart] AGP not available\n");
399 if (drmAgpEnable(ctx
->drmFD
, mode
) < 0) {
400 fprintf(stderr
, "[gart] AGP not enabled\n");
401 drmAgpRelease(ctx
->drmFD
);
405 fprintf(stderr
, "[gart] AGP enabled at %dx\n", ctx
->agpmode
);
411 * Allocate memory from the given pool. Grow the pool if needed and if
415 AllocFromPool(const DRIDriverContext
*ctx
, I830Rec
*pI830
,
416 I830MemRange
*result
, I830MemPool
*pool
,
417 long size
, unsigned long alignment
, int flags
)
419 long needed
, start
, end
;
421 if (!result
|| !pool
|| !size
)
424 /* Calculate how much space is needed. */
425 if (alignment
<= GTT_PAGE_SIZE
)
428 start
= ROUND_TO(pool
->Free
.Start
, alignment
);
429 end
= ROUND_TO(start
+ size
, alignment
);
430 needed
= end
- pool
->Free
.Start
;
432 if (needed
> pool
->Free
.Size
) {
436 result
->Start
= ROUND_TO(pool
->Free
.Start
, alignment
);
437 pool
->Free
.Start
+= needed
;
438 result
->End
= pool
->Free
.Start
;
440 pool
->Free
.Size
= pool
->Free
.End
- pool
->Free
.Start
;
441 result
->Size
= result
->End
- result
->Start
;
443 result
->Alignment
= alignment
;
447 static unsigned long AllocFromAGP(const DRIDriverContext
*ctx
, I830Rec
*pI830
, long size
, unsigned long alignment
, I830MemRange
*result
)
449 unsigned long start
, end
;
450 unsigned long newApStart
, newApEnd
;
452 if (!result
|| !size
)
458 start
= ROUND_TO(pI830
->MemoryAperture
.Start
, alignment
);
459 end
= ROUND_TO(start
+ size
, alignment
);
461 newApEnd
= pI830
->MemoryAperture
.End
;
463 ret
=drmAgpAlloc(ctx
->drmFD
, size
, 0, &(result
->Physical
), (drm_handle_t
*)&(result
->Key
));
467 fprintf(stderr
,"drmAgpAlloc failed %d\n", ret
);
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
;
478 result
->Offset
= start
;
479 result
->Alignment
= alignment
;
486 I830AllocVidMem(const DRIDriverContext
*ctx
, I830Rec
*pI830
, I830MemRange
*result
, I830MemPool
*pool
, long size
, unsigned long alignment
, int flags
)
493 /* Make sure these are initialised. */
501 if (pool
->Free
.Size
< size
)
502 return AllocFromAGP(ctx
, pI830
, size
, alignment
, result
);
505 ret
= AllocFromPool(ctx
, pI830
, result
, pool
, size
, alignment
, flags
);
508 return AllocFromAGP(ctx
, pI830
, size
, alignment
, result
);
513 static Bool
BindAgpRange(const DRIDriverContext
*ctx
, I830MemRange
*mem
)
521 return !drmAgpBind(ctx
->drmFD
, mem
->Key
, mem
->Offset
);
524 /* simple memory allocation routines needed */
525 /* put ring buffer in low memory */
526 /* need to allocate front, back, depth buffers aligned correctly,
527 allocate ring buffer,
532 I830AllocateMemory(const DRIDriverContext
*ctx
, I830Rec
*pI830
)
534 unsigned long size
, ret
;
535 unsigned long lines
, lineSize
, align
;
537 /* allocate ring buffer */
538 memset(pI830
->LpRing
, 0, sizeof(I830RingBuffer
));
539 pI830
->LpRing
->mem
.Key
= -1;
541 size
= PRIMARY_RINGBUFFER_SIZE
;
543 ret
= I830AllocVidMem(ctx
, pI830
, &pI830
->LpRing
->mem
, &pI830
->StolenPool
, size
, 0x1000, 0);
547 fprintf(stderr
,"unable to allocate ring buffer %ld\n", ret
);
551 pI830
->LpRing
->tail_mask
= pI830
->LpRing
->mem
.Size
- 1;
554 /* allocate front buffer */
555 memset(&(pI830
->FrontBuffer
), 0, sizeof(pI830
->FrontBuffer
));
556 pI830
->FrontBuffer
.Key
= -1;
557 pI830
->FrontBuffer
.Pitch
= ctx
->shared
.virtualWidth
;
561 lineSize
= ctx
->shared
.virtualWidth
* ctx
->cpp
;
562 lines
= (ctx
->shared
.virtualHeight
+ 15) / 16 * 16;
563 size
= lineSize
* lines
;
564 size
= ROUND_TO_PAGE(size
);
566 align
= GetBestTileAlignment(size
);
568 ret
= I830AllocVidMem(ctx
, pI830
, &pI830
->FrontBuffer
, &pI830
->StolenPool
, size
, align
, 0);
571 fprintf(stderr
,"unable to allocate front buffer %ld\n", ret
);
575 memset(&(pI830
->BackBuffer
), 0, sizeof(pI830
->BackBuffer
));
576 pI830
->BackBuffer
.Key
= -1;
577 pI830
->BackBuffer
.Pitch
= ctx
->shared
.virtualWidth
;
579 ret
= I830AllocVidMem(ctx
, pI830
, &pI830
->BackBuffer
, &pI830
->StolenPool
, size
, align
, 0);
582 fprintf(stderr
,"unable to allocate back buffer %ld\n", ret
);
586 memset(&(pI830
->DepthBuffer
), 0, sizeof(pI830
->DepthBuffer
));
587 pI830
->DepthBuffer
.Key
= -1;
588 pI830
->DepthBuffer
.Pitch
= ctx
->shared
.virtualWidth
;
590 ret
= I830AllocVidMem(ctx
, pI830
, &pI830
->DepthBuffer
, &pI830
->StolenPool
, size
, align
, 0);
593 fprintf(stderr
,"unable to allocate depth buffer %ld\n", ret
);
597 memset(&(pI830
->ContextMem
), 0, sizeof(pI830
->ContextMem
));
598 pI830
->ContextMem
.Key
= -1;
601 ret
= I830AllocVidMem(ctx
, pI830
, &pI830
->ContextMem
, &pI830
->StolenPool
, size
, align
, 0);
604 fprintf(stderr
,"unable to allocate context buffer %ld\n", ret
);
609 memset(&(pI830
->TexMem
), 0, sizeof(pI830
->TexMem
));
610 pI830
->TexMem
.Key
= -1;
613 ret
= AllocFromAGP(ctx
, pI830
, size
, align
, &pI830
->TexMem
);
616 fprintf(stderr
,"unable to allocate texture memory %ld\n", ret
);
625 I830BindMemory(const DRIDriverContext
*ctx
, I830Rec
*pI830
)
627 if (!BindAgpRange(ctx
, &pI830
->LpRing
->mem
))
629 if (!BindAgpRange(ctx
, &pI830
->FrontBuffer
))
631 if (!BindAgpRange(ctx
, &pI830
->BackBuffer
))
633 if (!BindAgpRange(ctx
, &pI830
->DepthBuffer
))
635 if (!BindAgpRange(ctx
, &pI830
->ContextMem
))
638 if (!BindAgpRange(ctx
, &pI830
->TexMem
))
644 static void SetupDRIMM(const DRIDriverContext
*ctx
, I830Rec
*pI830
)
646 unsigned long aperEnd
= ROUND_DOWN_TO(pI830
->aper_size
, GTT_PAGE_SIZE
) / GTT_PAGE_SIZE
;
647 unsigned long aperStart
= ROUND_TO(pI830
->aper_size
- KB(32768), GTT_PAGE_SIZE
) / GTT_PAGE_SIZE
;
649 fprintf(stderr
, "aper size is %08X\n", ctx
->shared
.fbSize
);
650 if (drmMMInit(ctx
->drmFD
, aperStart
, aperEnd
- aperStart
, DRM_BO_MEM_TT
)) {
652 "DRM MM Initialization Failed\n");
655 "DRM MM Initialized at offset 0x%lx length %d page\n", aperStart
, aperEnd
-aperStart
);
661 I830CleanupDma(const DRIDriverContext
*ctx
)
665 memset(&info
, 0, sizeof(drmI830Init
));
666 info
.func
= I830_CLEANUP_DMA
;
668 if (drmCommandWrite(ctx
->drmFD
, DRM_I830_INIT
,
669 &info
, sizeof(drmI830Init
))) {
670 fprintf(stderr
, "I830 Dma Cleanup Failed\n");
678 I830InitDma(const DRIDriverContext
*ctx
, I830Rec
*pI830
)
680 I830RingBuffer
*ring
= pI830
->LpRing
;
683 memset(&info
, 0, sizeof(drmI830Init
));
684 info
.func
= I830_INIT_DMA
;
686 info
.ring_start
= ring
->mem
.Start
+ pI830
->LinearAddr
;
687 info
.ring_end
= ring
->mem
.End
+ pI830
->LinearAddr
;
688 info
.ring_size
= ring
->mem
.Size
;
690 info
.mmio_offset
= (unsigned int)ctx
->MMIOStart
;
692 info
.sarea_priv_offset
= sizeof(drm_sarea_t
);
694 info
.front_offset
= pI830
->FrontBuffer
.Start
;
695 info
.back_offset
= pI830
->BackBuffer
.Start
;
696 info
.depth_offset
= pI830
->DepthBuffer
.Start
;
697 info
.w
= ctx
->shared
.virtualWidth
;
698 info
.h
= ctx
->shared
.virtualHeight
;
699 info
.pitch
= ctx
->shared
.virtualWidth
;
700 info
.back_pitch
= pI830
->BackBuffer
.Pitch
;
701 info
.depth_pitch
= pI830
->DepthBuffer
.Pitch
;
704 if (drmCommandWrite(ctx
->drmFD
, DRM_I830_INIT
,
705 &info
, sizeof(drmI830Init
))) {
707 "I830 Dma Initialization Failed\n");
714 static int I830CheckDRMVersion( const DRIDriverContext
*ctx
,
717 drmVersionPtr version
;
719 version
= drmGetVersion(ctx
->drmFD
);
722 int req_minor
, req_patch
;
727 if (version
->version_major
!= 1 ||
728 version
->version_minor
< req_minor
||
729 (version
->version_minor
== req_minor
&&
730 version
->version_patchlevel
< req_patch
)) {
731 /* Incompatible drm version */
733 "[dri] I830DRIScreenInit failed because of a version "
735 "[dri] i915.o kernel module version is %d.%d.%d "
736 "but version 1.%d.%d or newer is needed.\n"
737 "[dri] Disabling DRI.\n",
738 version
->version_major
,
739 version
->version_minor
,
740 version
->version_patchlevel
,
743 drmFreeVersion(version
);
747 pI830
->drmMinor
= version
->version_minor
;
748 drmFreeVersion(version
);
754 I830SetRingRegs(const DRIDriverContext
*ctx
, I830Rec
*pI830
)
757 unsigned char *MMIO
= ctx
->MMIOAddress
;
759 OUTREG(LP_RING
+ RING_LEN
, 0);
760 OUTREG(LP_RING
+ RING_TAIL
, 0);
761 OUTREG(LP_RING
+ RING_HEAD
, 0);
763 if ((long)(pI830
->LpRing
->mem
.Start
& I830_RING_START_MASK
) !=
764 pI830
->LpRing
->mem
.Start
) {
766 "I830SetRingRegs: Ring buffer start (%lx) violates its "
767 "mask (%x)\n", pI830
->LpRing
->mem
.Start
, I830_RING_START_MASK
);
769 /* Don't care about the old value. Reserved bits must be zero anyway. */
770 itemp
= pI830
->LpRing
->mem
.Start
& I830_RING_START_MASK
;
771 OUTREG(LP_RING
+ RING_START
, itemp
);
773 if (((pI830
->LpRing
->mem
.Size
- 4096) & I830_RING_NR_PAGES
) !=
774 pI830
->LpRing
->mem
.Size
- 4096) {
776 "I830SetRingRegs: Ring buffer size - 4096 (%lx) violates its "
777 "mask (%x)\n", pI830
->LpRing
->mem
.Size
- 4096,
780 /* Don't care about the old value. Reserved bits must be zero anyway. */
781 itemp
= (pI830
->LpRing
->mem
.Size
- 4096) & I830_RING_NR_PAGES
;
782 itemp
|= (RING_NO_REPORT
| RING_VALID
);
783 OUTREG(LP_RING
+ RING_LEN
, itemp
);
785 pI830
->LpRing
->head
= INREG(LP_RING
+ RING_HEAD
) & I830_HEAD_MASK
;
786 pI830
->LpRing
->tail
= INREG(LP_RING
+ RING_TAIL
);
787 pI830
->LpRing
->space
= pI830
->LpRing
->head
- (pI830
->LpRing
->tail
+ 8);
788 if (pI830
->LpRing
->space
< 0)
789 pI830
->LpRing
->space
+= pI830
->LpRing
->mem
.Size
;
791 SetFenceRegs(ctx
, pI830
);
793 /* RESET THE DISPLAY PIPE TO POINT TO THE FRONTBUFFER - hacky
795 OUTREG(DSPABASE
, pI830
->FrontBuffer
.Start
+ pI830
->LinearAddr
);
800 I830SetParam(const DRIDriverContext
*ctx
, int param
, int value
)
804 memset(&sp
, 0, sizeof(sp
));
808 if (drmCommandWrite(ctx
->drmFD
, DRM_I830_SETPARAM
, &sp
, sizeof(sp
))) {
809 fprintf(stderr
, "I830 SetParam Failed\n");
817 I830DRIMapScreenRegions(DRIDriverContext
*ctx
, I830Rec
*pI830
, drmI830Sarea
*sarea
)
820 "[drm] Mapping front buffer\n");
822 if (drmAddMap(ctx
->drmFD
,
823 (drm_handle_t
)(sarea
->front_offset
+ pI830
->LinearAddr
),
825 DRM_FRAME_BUFFER
, /*DRM_AGP,*/
827 &sarea
->front_handle
) < 0) {
829 "[drm] drmAddMap(front_handle) failed. Disabling DRI\n");
832 ctx
->shared
.hFrameBuffer
= sarea
->front_handle
;
833 ctx
->shared
.fbSize
= sarea
->front_size
;
834 fprintf(stderr
, "[drm] Front Buffer = 0x%08x\n",
835 sarea
->front_handle
);
837 if (drmAddMap(ctx
->drmFD
,
838 (drm_handle_t
)(sarea
->back_offset
),
839 sarea
->back_size
, DRM_AGP
, 0,
840 &sarea
->back_handle
) < 0) {
842 "[drm] drmAddMap(back_handle) failed. Disabling DRI\n");
845 fprintf(stderr
, "[drm] Back Buffer = 0x%08x\n",
848 if (drmAddMap(ctx
->drmFD
,
849 (drm_handle_t
)sarea
->depth_offset
,
850 sarea
->depth_size
, DRM_AGP
, 0,
851 &sarea
->depth_handle
) < 0) {
853 "[drm] drmAddMap(depth_handle) failed. Disabling DRI\n");
856 fprintf(stderr
, "[drm] Depth Buffer = 0x%08x\n",
857 sarea
->depth_handle
);
860 if (drmAddMap(ctx
->drmFD
,
861 (drm_handle_t
)sarea
->tex_offset
,
862 sarea
->tex_size
, DRM_AGP
, 0,
863 &sarea
->tex_handle
) < 0) {
865 "[drm] drmAddMap(tex_handle) failed. Disabling DRI\n");
868 fprintf(stderr
, "[drm] textures = 0x%08x\n",
876 I830DRIUnmapScreenRegions(const DRIDriverContext
*ctx
, I830Rec
*pI830
, drmI830Sarea
*sarea
)
879 if (sarea
->front_handle
) {
880 drmRmMap(ctx
->drmFD
, sarea
->front_handle
);
881 sarea
->front_handle
= 0;
884 if (sarea
->back_handle
) {
885 drmRmMap(ctx
->drmFD
, sarea
->back_handle
);
886 sarea
->back_handle
= 0;
888 if (sarea
->depth_handle
) {
889 drmRmMap(ctx
->drmFD
, sarea
->depth_handle
);
890 sarea
->depth_handle
= 0;
892 if (sarea
->tex_handle
) {
893 drmRmMap(ctx
->drmFD
, sarea
->tex_handle
);
894 sarea
->tex_handle
= 0;
900 I830InitTextureHeap(const DRIDriverContext
*ctx
, I830Rec
*pI830
, drmI830Sarea
*sarea
)
902 /* Start up the simple memory manager for agp space */
903 drmI830MemInitHeap drmHeap
;
904 drmHeap
.region
= I830_MEM_REGION_AGP
;
906 drmHeap
.size
= sarea
->tex_size
;
908 if (drmCommandWrite(ctx
->drmFD
, DRM_I830_INIT_HEAP
,
909 &drmHeap
, sizeof(drmHeap
))) {
911 "[drm] Failed to initialized agp heap manager\n");
914 "[drm] Initialized kernel agp heap manager, %d\n",
917 I830SetParam(ctx
, I830_SETPARAM_TEX_LRU_LOG_GRANULARITY
,
918 sarea
->log_tex_granularity
);
924 I830DRIDoMappings(DRIDriverContext
*ctx
, I830Rec
*pI830
, drmI830Sarea
*sarea
)
926 if (drmAddMap(ctx
->drmFD
,
927 (drm_handle_t
)pI830
->LpRing
->mem
.Start
,
928 pI830
->LpRing
->mem
.Size
, DRM_AGP
, 0,
929 &pI830
->ring_map
) < 0) {
931 "[drm] drmAddMap(ring_map) failed. Disabling DRI\n");
934 fprintf(stderr
, "[drm] ring buffer = 0x%08x\n",
937 if (I830InitDma(ctx
, pI830
) == FALSE
) {
941 /* init to zero to be safe */
943 I830DRIMapScreenRegions(ctx
, pI830
, sarea
);
944 SetupDRIMM(ctx
, pI830
);
947 I830InitTextureHeap(ctx
, pI830
, sarea
);
949 if (ctx
->pciDevice
!= PCI_CHIP_845_G
&&
950 ctx
->pciDevice
!= PCI_CHIP_I830_M
) {
951 I830SetParam(ctx
, I830_SETPARAM_USE_MI_BATCHBUFFER_START
, 1 );
954 /* Okay now initialize the dma engine */
956 pI830
->irq
= drmGetInterruptFromBusID(ctx
->drmFD
,
961 if (drmCtlInstHandler(ctx
->drmFD
, pI830
->irq
)) {
963 "[drm] failure adding irq handler\n");
969 "[drm] dma control initialized, using IRQ %d\n",
973 fprintf(stderr
, "[dri] visual configs initialized\n");
979 I830ClearScreen(DRIDriverContext
*ctx
, I830Rec
*pI830
, drmI830Sarea
*sarea
)
981 /* need to drmMap front and back buffers and zero them */
985 ret
= drmMap(ctx
->drmFD
,
992 fprintf(stderr
, "Unable to map front buffer\n");
996 drimemsetio((char *)map_addr
,
999 drmUnmap(map_addr
, sarea
->front_size
);
1002 ret
= drmMap(ctx
->drmFD
,
1009 fprintf(stderr
, "Unable to map back buffer\n");
1013 drimemsetio((char *)map_addr
,
1016 drmUnmap(map_addr
, sarea
->back_size
);
1022 I830ScreenInit(DRIDriverContext
*ctx
, I830Rec
*pI830
)
1025 I830DRIPtr pI830DRI
;
1026 drmI830Sarea
*pSAREAPriv
;
1029 drm_page_size
= getpagesize();
1031 pI830
->registerSize
= ctx
->MMIOSize
;
1032 /* This is a hack for now. We have to have more than a 4k page here
1033 * because of the size of the state. However, the state should be
1034 * in a per-context mapping. This will be added in the Mesa 3.5 port
1035 * of the I830 driver.
1037 ctx
->shared
.SAREASize
= SAREA_MAX
;
1039 /* Note that drmOpen will try to load the kernel module, if needed. */
1040 ctx
->drmFD
= drmOpen("i915", NULL
);
1041 if (ctx
->drmFD
< 0) {
1042 fprintf(stderr
, "[drm] drmOpen failed\n");
1046 if ((err
= drmSetBusid(ctx
->drmFD
, ctx
->pciBusID
)) < 0) {
1047 fprintf(stderr
, "[drm] drmSetBusid failed (%d, %s), %s\n",
1048 ctx
->drmFD
, ctx
->pciBusID
, strerror(-err
));
1052 if (drmAddMap( ctx
->drmFD
,
1054 ctx
->shared
.SAREASize
,
1057 &ctx
->shared
.hSAREA
) < 0)
1059 fprintf(stderr
, "[drm] drmAddMap failed\n");
1063 fprintf(stderr
, "[drm] added %d byte SAREA at 0x%08x\n",
1064 ctx
->shared
.SAREASize
, ctx
->shared
.hSAREA
);
1066 if (drmMap( ctx
->drmFD
,
1068 ctx
->shared
.SAREASize
,
1069 (drmAddressPtr
)(&ctx
->pSAREA
)) < 0)
1071 fprintf(stderr
, "[drm] drmMap failed\n");
1076 memset(ctx
->pSAREA
, 0, ctx
->shared
.SAREASize
);
1077 fprintf(stderr
, "[drm] mapped SAREA 0x%08x to %p, size %d\n",
1078 ctx
->shared
.hSAREA
, ctx
->pSAREA
, ctx
->shared
.SAREASize
);
1081 if (drmAddMap(ctx
->drmFD
,
1086 &pI830
->registerHandle
) < 0) {
1087 fprintf(stderr
, "[drm] drmAddMap mmio failed\n");
1091 "[drm] register handle = 0x%08x\n", pI830
->registerHandle
);
1094 if (!I830CheckDRMVersion(ctx
, pI830
)) {
1098 /* Create a 'server' context so we can grab the lock for
1099 * initialization ioctls.
1101 if ((err
= drmCreateContext(ctx
->drmFD
, &ctx
->serverContext
)) != 0) {
1102 fprintf(stderr
, "%s: drmCreateContext failed %d\n", __FUNCTION__
, err
);
1106 DRM_LOCK(ctx
->drmFD
, ctx
->pSAREA
, ctx
->serverContext
, 0);
1108 /* Initialize the SAREA private data structure */
1109 pSAREAPriv
= (drmI830Sarea
*)(((char*)ctx
->pSAREA
) +
1110 sizeof(drm_sarea_t
));
1111 memset(pSAREAPriv
, 0, sizeof(*pSAREAPriv
));
1113 pI830
->StolenMemory
.Size
= I830DetectMemory(ctx
, pI830
);
1114 pI830
->StolenMemory
.Start
= 0;
1115 pI830
->StolenMemory
.End
= pI830
->StolenMemory
.Size
;
1117 pI830
->MemoryAperture
.Start
= pI830
->StolenMemory
.End
;
1118 pI830
->MemoryAperture
.End
= KB(40000);
1119 pI830
->MemoryAperture
.Size
= pI830
->MemoryAperture
.End
- pI830
->MemoryAperture
.Start
;
1121 pI830
->StolenPool
.Fixed
= pI830
->StolenMemory
;
1122 pI830
->StolenPool
.Total
= pI830
->StolenMemory
;
1123 pI830
->StolenPool
.Free
= pI830
->StolenPool
.Total
;
1124 pI830
->FreeMemory
= pI830
->StolenPool
.Total
.Size
;
1126 if (!AgpInit(ctx
, pI830
))
1129 if (I830AllocateMemory(ctx
, pI830
) == FALSE
)
1134 if (I830BindMemory(ctx
, pI830
) == FALSE
)
1139 pSAREAPriv
->rotated_offset
= -1;
1140 pSAREAPriv
->rotated_size
= 0;
1141 pSAREAPriv
->rotated_pitch
= ctx
->shared
.virtualWidth
;
1143 pSAREAPriv
->front_offset
= pI830
->FrontBuffer
.Start
;
1144 pSAREAPriv
->front_size
= pI830
->FrontBuffer
.Size
;
1145 pSAREAPriv
->width
= ctx
->shared
.virtualWidth
;
1146 pSAREAPriv
->height
= ctx
->shared
.virtualHeight
;
1147 pSAREAPriv
->pitch
= ctx
->shared
.virtualWidth
;
1148 pSAREAPriv
->virtualX
= ctx
->shared
.virtualWidth
;
1149 pSAREAPriv
->virtualY
= ctx
->shared
.virtualHeight
;
1150 pSAREAPriv
->back_offset
= pI830
->BackBuffer
.Start
;
1151 pSAREAPriv
->back_size
= pI830
->BackBuffer
.Size
;
1152 pSAREAPriv
->depth_offset
= pI830
->DepthBuffer
.Start
;
1153 pSAREAPriv
->depth_size
= pI830
->DepthBuffer
.Size
;
1155 pSAREAPriv
->tex_offset
= pI830
->TexMem
.Start
;
1156 pSAREAPriv
->tex_size
= pI830
->TexMem
.Size
;
1158 pSAREAPriv
->log_tex_granularity
= pI830
->TexGranularity
;
1160 ctx
->driverClientMsg
= malloc(sizeof(I830DRIRec
));
1161 ctx
->driverClientMsgSize
= sizeof(I830DRIRec
);
1162 pI830DRI
= (I830DRIPtr
)ctx
->driverClientMsg
;
1163 pI830DRI
->deviceID
= pI830
->Chipset
;
1164 pI830DRI
->regsSize
= I830_REG_SIZE
;
1165 pI830DRI
->width
= ctx
->shared
.virtualWidth
;
1166 pI830DRI
->height
= ctx
->shared
.virtualHeight
;
1167 pI830DRI
->mem
= ctx
->shared
.fbSize
;
1168 pI830DRI
->cpp
= ctx
->cpp
;
1170 pI830DRI
->bitsPerPixel
= ctx
->bpp
;
1171 pI830DRI
->sarea_priv_offset
= sizeof(drm_sarea_t
);
1173 err
= I830DRIDoMappings(ctx
, pI830
, pSAREAPriv
);
1177 I830SetupMemoryTiling(ctx
, pI830
);
1179 /* Quick hack to clear the front & back buffers. Could also use
1180 * the clear ioctl to do this, but would need to setup hw state
1183 I830ClearScreen(ctx
, pI830
, pSAREAPriv
);
1185 I830SetRingRegs(ctx
, pI830
);
1192 * \brief Validate the fbdev mode.
1194 * \param ctx display handle.
1196 * \return one on success, or zero on failure.
1198 * Saves some registers and returns 1.
1200 * \sa radeonValidateMode().
1202 static int i830ValidateMode( const DRIDriverContext
*ctx
)
1208 * \brief Examine mode returned by fbdev.
1210 * \param ctx display handle.
1212 * \return one on success, or zero on failure.
1214 * Restores registers that fbdev has clobbered and returns 1.
1216 * \sa i810ValidateMode().
1218 static int i830PostValidateMode( const DRIDriverContext
*ctx
)
1220 I830Rec
*pI830
= ctx
->driverPrivate
;
1222 I830SetRingRegs(ctx
, pI830
);
1228 * \brief Initialize the framebuffer device mode
1230 * \param ctx display handle.
1232 * \return one on success, or zero on failure.
1234 * Fills in \p info with some default values and some information from \p ctx
1235 * and then calls I810ScreenInit() for the screen initialization.
1237 * Before exiting clears the framebuffer memory accessing it directly.
1239 static int i830InitFBDev( DRIDriverContext
*ctx
)
1241 I830Rec
*pI830
= calloc(1, sizeof(I830Rec
));
1245 int dummy
= ctx
->shared
.virtualWidth
;
1247 switch (ctx
->bpp
/ 8) {
1248 case 1: dummy
= (ctx
->shared
.virtualWidth
+ 127) & ~127; break;
1249 case 2: dummy
= (ctx
->shared
.virtualWidth
+ 31) & ~31; break;
1251 case 4: dummy
= (ctx
->shared
.virtualWidth
+ 15) & ~15; break;
1254 ctx
->shared
.virtualWidth
= dummy
;
1255 ctx
->shared
.Width
= ctx
->shared
.virtualWidth
;
1259 for (i
= 0; pitches
[i
] != 0; i
++) {
1260 if (pitches
[i
] >= ctx
->shared
.virtualWidth
) {
1261 ctx
->shared
.virtualWidth
= pitches
[i
];
1266 ctx
->driverPrivate
= (void *)pI830
;
1268 pI830
->LpRing
= calloc(1, sizeof(I830RingBuffer
));
1269 pI830
->Chipset
= ctx
->chipset
;
1270 pI830
->LinearAddr
= ctx
->FBStart
;
1272 if (!I830ScreenInit( ctx
, pI830
))
1281 * \brief The screen is being closed, so clean up any state and free any
1282 * resources used by the DRI.
1284 * \param ctx display handle.
1286 * Unmaps the SAREA, closes the DRM device file descriptor and frees the driver
1289 static void i830HaltFBDev( DRIDriverContext
*ctx
)
1291 drmI830Sarea
*pSAREAPriv
;
1292 I830Rec
*pI830
= ctx
->driverPrivate
;
1295 drmCtlUninstHandler(ctx
->drmFD
);
1298 I830CleanupDma(ctx
);
1300 pSAREAPriv
= (drmI830Sarea
*)(((char*)ctx
->pSAREA
) +
1301 sizeof(drm_sarea_t
));
1303 I830DRIUnmapScreenRegions(ctx
, pI830
, pSAREAPriv
);
1304 drmUnmap( ctx
->pSAREA
, ctx
->shared
.SAREASize
);
1305 drmClose(ctx
->drmFD
);
1307 if (ctx
->driverPrivate
) {
1308 free(ctx
->driverPrivate
);
1309 ctx
->driverPrivate
= 0;
1314 extern void i810NotifyFocus( int );
1317 * \brief Exported driver interface for Mini GLX.
1321 const struct DRIDriverRec __driDriver
= {
1323 i830PostValidateMode
,
1326 NULL
,//I830EngineShutdown,
1327 NULL
, //I830EngineRestore,