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
;
300 memset(&host_bridge
, 0, sizeof(host_bridge
));
302 pci_device_cfg_read_u32(&host_bridge
, &gmch_ctrl
, I830_GMCH_CTRL
);
304 /* We need to reduce the stolen size, by the GTT and the popup.
305 * The GTT varying according the the FbMapSize and the popup is 4KB */
306 range
= (ctx
->shared
.fbSize
/ (1024*1024)) + 4;
308 if (IS_I85X(pI830
) || IS_I865G(pI830
) || IS_I9XX(pI830
)) {
309 switch (gmch_ctrl
& I830_GMCH_GMS_MASK
) {
310 case I855_GMCH_GMS_STOLEN_1M
:
311 memsize
= MB(1) - KB(range
);
313 case I855_GMCH_GMS_STOLEN_4M
:
314 memsize
= MB(4) - KB(range
);
316 case I855_GMCH_GMS_STOLEN_8M
:
317 memsize
= MB(8) - KB(range
);
319 case I855_GMCH_GMS_STOLEN_16M
:
320 memsize
= MB(16) - KB(range
);
322 case I855_GMCH_GMS_STOLEN_32M
:
323 memsize
= MB(32) - KB(range
);
325 case I915G_GMCH_GMS_STOLEN_48M
:
327 memsize
= MB(48) - KB(range
);
329 case I915G_GMCH_GMS_STOLEN_64M
:
331 memsize
= MB(64) - KB(range
);
335 switch (gmch_ctrl
& I830_GMCH_GMS_MASK
) {
336 case I830_GMCH_GMS_STOLEN_512
:
337 memsize
= KB(512) - KB(range
);
339 case I830_GMCH_GMS_STOLEN_1024
:
340 memsize
= MB(1) - KB(range
);
342 case I830_GMCH_GMS_STOLEN_8192
:
343 memsize
= MB(8) - KB(range
);
345 case I830_GMCH_GMS_LOCAL
:
347 xf86DrvMsg(pScrn
->scrnIndex
, X_WARNING
,
348 "Local memory found, but won't be used.\n");
354 "detected %d kB stolen memory.\n", memsize
/ 1024);
357 "no video memory detected.\n");
362 static int AgpInit(const DRIDriverContext
*ctx
, I830Rec
*info
)
364 unsigned long mode
= 0x4;
366 if (drmAgpAcquire(ctx
->drmFD
) < 0) {
367 fprintf(stderr
, "[gart] AGP not available\n");
371 if (drmAgpEnable(ctx
->drmFD
, mode
) < 0) {
372 fprintf(stderr
, "[gart] AGP not enabled\n");
373 drmAgpRelease(ctx
->drmFD
);
377 fprintf(stderr
, "[gart] AGP enabled at %dx\n", ctx
->agpmode
);
383 * Allocate memory from the given pool. Grow the pool if needed and if
387 AllocFromPool(const DRIDriverContext
*ctx
, I830Rec
*pI830
,
388 I830MemRange
*result
, I830MemPool
*pool
,
389 long size
, unsigned long alignment
, int flags
)
391 long needed
, start
, end
;
393 if (!result
|| !pool
|| !size
)
396 /* Calculate how much space is needed. */
397 if (alignment
<= GTT_PAGE_SIZE
)
400 start
= ROUND_TO(pool
->Free
.Start
, alignment
);
401 end
= ROUND_TO(start
+ size
, alignment
);
402 needed
= end
- pool
->Free
.Start
;
404 if (needed
> pool
->Free
.Size
) {
408 result
->Start
= ROUND_TO(pool
->Free
.Start
, alignment
);
409 pool
->Free
.Start
+= needed
;
410 result
->End
= pool
->Free
.Start
;
412 pool
->Free
.Size
= pool
->Free
.End
- pool
->Free
.Start
;
413 result
->Size
= result
->End
- result
->Start
;
415 result
->Alignment
= alignment
;
419 static unsigned long AllocFromAGP(const DRIDriverContext
*ctx
, I830Rec
*pI830
, long size
, unsigned long alignment
, I830MemRange
*result
)
421 unsigned long start
, end
;
422 unsigned long newApStart
, newApEnd
;
424 if (!result
|| !size
)
430 start
= ROUND_TO(pI830
->MemoryAperture
.Start
, alignment
);
431 end
= ROUND_TO(start
+ size
, alignment
);
433 newApEnd
= pI830
->MemoryAperture
.End
;
435 ret
=drmAgpAlloc(ctx
->drmFD
, size
, 0, &(result
->Physical
), (drm_handle_t
*)&(result
->Key
));
439 fprintf(stderr
,"drmAgpAlloc failed %d\n", ret
);
442 pI830
->allocatedMemory
+= size
;
443 pI830
->MemoryAperture
.Start
= newApStart
;
444 pI830
->MemoryAperture
.End
= newApEnd
;
445 pI830
->MemoryAperture
.Size
= newApEnd
- newApStart
;
446 // pI830->FreeMemory -= size;
447 result
->Start
= start
;
448 result
->End
= start
+ size
;
450 result
->Offset
= start
;
451 result
->Alignment
= alignment
;
458 I830AllocVidMem(const DRIDriverContext
*ctx
, I830Rec
*pI830
,
459 I830MemRange
*result
, I830MemPool
*pool
, long size
,
460 unsigned long alignment
, int flags
)
467 /* Make sure these are initialised. */
475 if (pool
->Free
.Size
< size
) {
476 ret
= AllocFromAGP(ctx
, pI830
, size
, alignment
, result
);
479 ret
= AllocFromPool(ctx
, pI830
, result
, pool
, size
, alignment
, flags
);
481 ret
= AllocFromAGP(ctx
, pI830
, size
, alignment
, result
);
486 static Bool
BindAgpRange(const DRIDriverContext
*ctx
, I830MemRange
*mem
)
494 return !drmAgpBind(ctx
->drmFD
, mem
->Key
, mem
->Offset
);
497 /* simple memory allocation routines needed */
498 /* put ring buffer in low memory */
499 /* need to allocate front, back, depth buffers aligned correctly,
500 allocate ring buffer,
505 I830AllocateMemory(const DRIDriverContext
*ctx
, I830Rec
*pI830
)
507 unsigned long size
, ret
;
508 unsigned long lines
, lineSize
, align
;
510 /* allocate ring buffer */
511 memset(pI830
->LpRing
, 0, sizeof(I830RingBuffer
));
512 pI830
->LpRing
->mem
.Key
= -1;
514 size
= PRIMARY_RINGBUFFER_SIZE
;
516 ret
= I830AllocVidMem(ctx
, pI830
, &pI830
->LpRing
->mem
, &pI830
->StolenPool
, size
, 0x1000, 0);
520 fprintf(stderr
,"unable to allocate ring buffer %ld\n", ret
);
524 pI830
->LpRing
->tail_mask
= pI830
->LpRing
->mem
.Size
- 1;
527 /* allocate front buffer */
528 memset(&(pI830
->FrontBuffer
), 0, sizeof(pI830
->FrontBuffer
));
529 pI830
->FrontBuffer
.Key
= -1;
530 pI830
->FrontBuffer
.Pitch
= ctx
->shared
.virtualWidth
;
534 lineSize
= ctx
->shared
.virtualWidth
* ctx
->cpp
;
535 lines
= (ctx
->shared
.virtualHeight
+ 15) / 16 * 16;
536 size
= lineSize
* lines
;
537 size
= ROUND_TO_PAGE(size
);
539 align
= GetBestTileAlignment(size
);
541 ret
= I830AllocVidMem(ctx
, pI830
, &pI830
->FrontBuffer
, &pI830
->StolenPool
, size
, align
, 0);
544 fprintf(stderr
,"unable to allocate front buffer %ld\n", ret
);
548 memset(&(pI830
->BackBuffer
), 0, sizeof(pI830
->BackBuffer
));
549 pI830
->BackBuffer
.Key
= -1;
550 pI830
->BackBuffer
.Pitch
= ctx
->shared
.virtualWidth
;
552 ret
= I830AllocVidMem(ctx
, pI830
, &pI830
->BackBuffer
, &pI830
->StolenPool
, size
, align
, 0);
555 fprintf(stderr
,"unable to allocate back buffer %ld\n", ret
);
559 memset(&(pI830
->DepthBuffer
), 0, sizeof(pI830
->DepthBuffer
));
560 pI830
->DepthBuffer
.Key
= -1;
561 pI830
->DepthBuffer
.Pitch
= ctx
->shared
.virtualWidth
;
563 ret
= I830AllocVidMem(ctx
, pI830
, &pI830
->DepthBuffer
, &pI830
->StolenPool
, size
, align
, 0);
566 fprintf(stderr
,"unable to allocate depth buffer %ld\n", ret
);
570 memset(&(pI830
->ContextMem
), 0, sizeof(pI830
->ContextMem
));
571 pI830
->ContextMem
.Key
= -1;
574 ret
= I830AllocVidMem(ctx
, pI830
, &pI830
->ContextMem
, &pI830
->StolenPool
, size
, align
, 0);
577 fprintf(stderr
,"unable to allocate context buffer %ld\n", ret
);
581 memset(&(pI830
->TexMem
), 0, sizeof(pI830
->TexMem
));
582 pI830
->TexMem
.Key
= -1;
585 ret
= AllocFromAGP(ctx
, pI830
, size
, align
, &pI830
->TexMem
);
588 fprintf(stderr
,"unable to allocate texture memory %ld\n", ret
);
596 I830BindMemory(const DRIDriverContext
*ctx
, I830Rec
*pI830
)
598 if (!BindAgpRange(ctx
, &pI830
->LpRing
->mem
))
600 if (!BindAgpRange(ctx
, &pI830
->FrontBuffer
))
602 if (!BindAgpRange(ctx
, &pI830
->BackBuffer
))
604 if (!BindAgpRange(ctx
, &pI830
->DepthBuffer
))
606 if (!BindAgpRange(ctx
, &pI830
->ContextMem
))
608 if (!BindAgpRange(ctx
, &pI830
->TexMem
))
615 I830CleanupDma(const DRIDriverContext
*ctx
)
619 memset(&info
, 0, sizeof(drmI830Init
));
620 info
.func
= I830_CLEANUP_DMA
;
622 if (drmCommandWrite(ctx
->drmFD
, DRM_I830_INIT
,
623 &info
, sizeof(drmI830Init
))) {
624 fprintf(stderr
, "I830 Dma Cleanup Failed\n");
632 I830InitDma(const DRIDriverContext
*ctx
, I830Rec
*pI830
)
634 I830RingBuffer
*ring
= pI830
->LpRing
;
637 memset(&info
, 0, sizeof(drmI830Init
));
638 info
.func
= I830_INIT_DMA
;
640 info
.ring_start
= ring
->mem
.Start
+ pI830
->LinearAddr
;
641 info
.ring_end
= ring
->mem
.End
+ pI830
->LinearAddr
;
642 info
.ring_size
= ring
->mem
.Size
;
644 info
.mmio_offset
= (unsigned int)ctx
->MMIOStart
;
646 info
.sarea_priv_offset
= sizeof(drm_sarea_t
);
648 info
.front_offset
= pI830
->FrontBuffer
.Start
;
649 info
.back_offset
= pI830
->BackBuffer
.Start
;
650 info
.depth_offset
= pI830
->DepthBuffer
.Start
;
651 info
.w
= ctx
->shared
.virtualWidth
;
652 info
.h
= ctx
->shared
.virtualHeight
;
653 info
.pitch
= ctx
->shared
.virtualWidth
;
654 info
.back_pitch
= pI830
->BackBuffer
.Pitch
;
655 info
.depth_pitch
= pI830
->DepthBuffer
.Pitch
;
658 if (drmCommandWrite(ctx
->drmFD
, DRM_I830_INIT
,
659 &info
, sizeof(drmI830Init
))) {
661 "I830 Dma Initialization Failed\n");
668 static int I830CheckDRMVersion( const DRIDriverContext
*ctx
,
671 drmVersionPtr version
;
673 version
= drmGetVersion(ctx
->drmFD
);
676 int req_minor
, req_patch
;
681 if (version
->version_major
!= 1 ||
682 version
->version_minor
< req_minor
||
683 (version
->version_minor
== req_minor
&&
684 version
->version_patchlevel
< req_patch
)) {
685 /* Incompatible drm version */
687 "[dri] I830DRIScreenInit failed because of a version "
689 "[dri] i915.o kernel module version is %d.%d.%d "
690 "but version 1.%d.%d or newer is needed.\n"
691 "[dri] Disabling DRI.\n",
692 version
->version_major
,
693 version
->version_minor
,
694 version
->version_patchlevel
,
697 drmFreeVersion(version
);
701 pI830
->drmMinor
= version
->version_minor
;
702 drmFreeVersion(version
);
708 I830SetRingRegs(const DRIDriverContext
*ctx
, I830Rec
*pI830
)
711 unsigned char *MMIO
= ctx
->MMIOAddress
;
713 OUTREG(LP_RING
+ RING_LEN
, 0);
714 OUTREG(LP_RING
+ RING_TAIL
, 0);
715 OUTREG(LP_RING
+ RING_HEAD
, 0);
717 if ((long)(pI830
->LpRing
->mem
.Start
& I830_RING_START_MASK
) !=
718 pI830
->LpRing
->mem
.Start
) {
720 "I830SetRingRegs: Ring buffer start (%lx) violates its "
721 "mask (%x)\n", pI830
->LpRing
->mem
.Start
, I830_RING_START_MASK
);
723 /* Don't care about the old value. Reserved bits must be zero anyway. */
724 itemp
= pI830
->LpRing
->mem
.Start
& I830_RING_START_MASK
;
725 OUTREG(LP_RING
+ RING_START
, itemp
);
727 if (((pI830
->LpRing
->mem
.Size
- 4096) & I830_RING_NR_PAGES
) !=
728 pI830
->LpRing
->mem
.Size
- 4096) {
730 "I830SetRingRegs: Ring buffer size - 4096 (%lx) violates its "
731 "mask (%x)\n", pI830
->LpRing
->mem
.Size
- 4096,
734 /* Don't care about the old value. Reserved bits must be zero anyway. */
735 itemp
= (pI830
->LpRing
->mem
.Size
- 4096) & I830_RING_NR_PAGES
;
736 itemp
|= (RING_NO_REPORT
| RING_VALID
);
737 OUTREG(LP_RING
+ RING_LEN
, itemp
);
739 pI830
->LpRing
->head
= INREG(LP_RING
+ RING_HEAD
) & I830_HEAD_MASK
;
740 pI830
->LpRing
->tail
= INREG(LP_RING
+ RING_TAIL
);
741 pI830
->LpRing
->space
= pI830
->LpRing
->head
- (pI830
->LpRing
->tail
+ 8);
742 if (pI830
->LpRing
->space
< 0)
743 pI830
->LpRing
->space
+= pI830
->LpRing
->mem
.Size
;
745 SetFenceRegs(ctx
, pI830
);
747 /* RESET THE DISPLAY PIPE TO POINT TO THE FRONTBUFFER - hacky
749 OUTREG(DSPABASE
, pI830
->FrontBuffer
.Start
+ pI830
->LinearAddr
);
754 I830SetParam(const DRIDriverContext
*ctx
, int param
, int value
)
758 memset(&sp
, 0, sizeof(sp
));
762 if (drmCommandWrite(ctx
->drmFD
, DRM_I830_SETPARAM
, &sp
, sizeof(sp
))) {
763 fprintf(stderr
, "I830 SetParam Failed\n");
771 I830DRIMapScreenRegions(DRIDriverContext
*ctx
, I830Rec
*pI830
, drmI830Sarea
*sarea
)
774 "[drm] Mapping front buffer\n");
776 if (drmAddMap(ctx
->drmFD
,
777 (drm_handle_t
)(sarea
->front_offset
+ pI830
->LinearAddr
),
779 DRM_FRAME_BUFFER
, /*DRM_AGP,*/
781 &sarea
->front_handle
) < 0) {
783 "[drm] drmAddMap(front_handle) failed. Disabling DRI\n");
786 ctx
->shared
.hFrameBuffer
= sarea
->front_handle
;
787 ctx
->shared
.fbSize
= sarea
->front_size
;
788 fprintf(stderr
, "[drm] Front Buffer = 0x%08x\n",
789 sarea
->front_handle
);
791 if (drmAddMap(ctx
->drmFD
,
792 (drm_handle_t
)(sarea
->back_offset
),
793 sarea
->back_size
, DRM_AGP
, 0,
794 &sarea
->back_handle
) < 0) {
796 "[drm] drmAddMap(back_handle) failed. Disabling DRI\n");
799 fprintf(stderr
, "[drm] Back Buffer = 0x%08x\n",
802 if (drmAddMap(ctx
->drmFD
,
803 (drm_handle_t
)sarea
->depth_offset
,
804 sarea
->depth_size
, DRM_AGP
, 0,
805 &sarea
->depth_handle
) < 0) {
807 "[drm] drmAddMap(depth_handle) failed. Disabling DRI\n");
810 fprintf(stderr
, "[drm] Depth Buffer = 0x%08x\n",
811 sarea
->depth_handle
);
813 if (drmAddMap(ctx
->drmFD
,
814 (drm_handle_t
)sarea
->tex_offset
,
815 sarea
->tex_size
, DRM_AGP
, 0,
816 &sarea
->tex_handle
) < 0) {
818 "[drm] drmAddMap(tex_handle) failed. Disabling DRI\n");
821 fprintf(stderr
, "[drm] textures = 0x%08x\n",
829 I830DRIUnmapScreenRegions(const DRIDriverContext
*ctx
, I830Rec
*pI830
, drmI830Sarea
*sarea
)
832 if (sarea
->front_handle
) {
833 drmRmMap(ctx
->drmFD
, sarea
->front_handle
);
834 sarea
->front_handle
= 0;
837 if (sarea
->back_handle
) {
838 drmRmMap(ctx
->drmFD
, sarea
->back_handle
);
839 sarea
->back_handle
= 0;
841 if (sarea
->depth_handle
) {
842 drmRmMap(ctx
->drmFD
, sarea
->depth_handle
);
843 sarea
->depth_handle
= 0;
845 if (sarea
->tex_handle
) {
846 drmRmMap(ctx
->drmFD
, sarea
->tex_handle
);
847 sarea
->tex_handle
= 0;
852 I830InitTextureHeap(const DRIDriverContext
*ctx
, I830Rec
*pI830
, drmI830Sarea
*sarea
)
854 /* Start up the simple memory manager for agp space */
855 drmI830MemInitHeap drmHeap
;
856 drmHeap
.region
= I830_MEM_REGION_AGP
;
858 drmHeap
.size
= sarea
->tex_size
;
860 if (drmCommandWrite(ctx
->drmFD
, DRM_I830_INIT_HEAP
,
861 &drmHeap
, sizeof(drmHeap
))) {
863 "[drm] Failed to initialized agp heap manager\n");
866 "[drm] Initialized kernel agp heap manager, %d\n",
869 I830SetParam(ctx
, I830_SETPARAM_TEX_LRU_LOG_GRANULARITY
,
870 sarea
->log_tex_granularity
);
875 I830DRIDoMappings(DRIDriverContext
*ctx
, I830Rec
*pI830
, drmI830Sarea
*sarea
)
877 if (drmAddMap(ctx
->drmFD
,
878 (drm_handle_t
)pI830
->LpRing
->mem
.Start
,
879 pI830
->LpRing
->mem
.Size
, DRM_AGP
, 0,
880 &pI830
->ring_map
) < 0) {
882 "[drm] drmAddMap(ring_map) failed. Disabling DRI\n");
885 fprintf(stderr
, "[drm] ring buffer = 0x%08x\n",
888 if (I830InitDma(ctx
, pI830
) == FALSE
) {
892 /* init to zero to be safe */
894 I830DRIMapScreenRegions(ctx
, pI830
, sarea
);
895 I830InitTextureHeap(ctx
, pI830
, sarea
);
897 if (ctx
->pciDevice
!= PCI_CHIP_845_G
&&
898 ctx
->pciDevice
!= PCI_CHIP_I830_M
) {
899 I830SetParam(ctx
, I830_SETPARAM_USE_MI_BATCHBUFFER_START
, 1 );
902 /* Okay now initialize the dma engine */
904 pI830
->irq
= drmGetInterruptFromBusID(ctx
->drmFD
,
909 if (drmCtlInstHandler(ctx
->drmFD
, pI830
->irq
)) {
911 "[drm] failure adding irq handler\n");
917 "[drm] dma control initialized, using IRQ %d\n",
921 fprintf(stderr
, "[dri] visual configs initialized\n");
927 I830ClearScreen(DRIDriverContext
*ctx
, I830Rec
*pI830
, drmI830Sarea
*sarea
)
929 /* need to drmMap front and back buffers and zero them */
933 ret
= drmMap(ctx
->drmFD
,
940 fprintf(stderr
, "Unable to map front buffer\n");
944 drimemsetio((char *)map_addr
,
947 drmUnmap(map_addr
, sarea
->front_size
);
950 ret
= drmMap(ctx
->drmFD
,
957 fprintf(stderr
, "Unable to map back buffer\n");
961 drimemsetio((char *)map_addr
,
964 drmUnmap(map_addr
, sarea
->back_size
);
970 I830ScreenInit(DRIDriverContext
*ctx
, I830Rec
*pI830
)
974 drmI830Sarea
*pSAREAPriv
;
977 drm_page_size
= getpagesize();
979 pI830
->registerSize
= ctx
->MMIOSize
;
980 /* This is a hack for now. We have to have more than a 4k page here
981 * because of the size of the state. However, the state should be
982 * in a per-context mapping. This will be added in the Mesa 3.5 port
983 * of the I830 driver.
985 ctx
->shared
.SAREASize
= SAREA_MAX
;
987 /* Note that drmOpen will try to load the kernel module, if needed. */
988 ctx
->drmFD
= drmOpen("i915", NULL
);
989 if (ctx
->drmFD
< 0) {
990 fprintf(stderr
, "[drm] drmOpen failed\n");
994 if ((err
= drmSetBusid(ctx
->drmFD
, ctx
->pciBusID
)) < 0) {
995 fprintf(stderr
, "[drm] drmSetBusid failed (%d, %s), %s\n",
996 ctx
->drmFD
, ctx
->pciBusID
, strerror(-err
));
1000 if (drmAddMap( ctx
->drmFD
,
1002 ctx
->shared
.SAREASize
,
1005 &ctx
->shared
.hSAREA
) < 0)
1007 fprintf(stderr
, "[drm] drmAddMap failed\n");
1011 fprintf(stderr
, "[drm] added %d byte SAREA at 0x%08x\n",
1012 ctx
->shared
.SAREASize
, ctx
->shared
.hSAREA
);
1014 if (drmMap( ctx
->drmFD
,
1016 ctx
->shared
.SAREASize
,
1017 (drmAddressPtr
)(&ctx
->pSAREA
)) < 0)
1019 fprintf(stderr
, "[drm] drmMap failed\n");
1024 memset(ctx
->pSAREA
, 0, ctx
->shared
.SAREASize
);
1025 fprintf(stderr
, "[drm] mapped SAREA 0x%08x to %p, size %d\n",
1026 ctx
->shared
.hSAREA
, ctx
->pSAREA
, ctx
->shared
.SAREASize
);
1029 if (drmAddMap(ctx
->drmFD
,
1034 &pI830
->registerHandle
) < 0) {
1035 fprintf(stderr
, "[drm] drmAddMap mmio failed\n");
1039 "[drm] register handle = 0x%08x\n", pI830
->registerHandle
);
1042 if (!I830CheckDRMVersion(ctx
, pI830
)) {
1046 /* Create a 'server' context so we can grab the lock for
1047 * initialization ioctls.
1049 if ((err
= drmCreateContext(ctx
->drmFD
, &ctx
->serverContext
)) != 0) {
1050 fprintf(stderr
, "%s: drmCreateContext failed %d\n", __FUNCTION__
, err
);
1054 DRM_LOCK(ctx
->drmFD
, ctx
->pSAREA
, ctx
->serverContext
, 0);
1056 /* Initialize the SAREA private data structure */
1057 pSAREAPriv
= (drmI830Sarea
*)(((char*)ctx
->pSAREA
) +
1058 sizeof(drm_sarea_t
));
1059 memset(pSAREAPriv
, 0, sizeof(*pSAREAPriv
));
1061 pI830
->StolenMemory
.Size
= I830DetectMemory(ctx
, pI830
);
1062 pI830
->StolenMemory
.Start
= 0;
1063 pI830
->StolenMemory
.End
= pI830
->StolenMemory
.Size
;
1065 pI830
->MemoryAperture
.Start
= pI830
->StolenMemory
.End
;
1066 pI830
->MemoryAperture
.End
= KB(40000);
1067 pI830
->MemoryAperture
.Size
= pI830
->MemoryAperture
.End
- pI830
->MemoryAperture
.Start
;
1069 pI830
->StolenPool
.Fixed
= pI830
->StolenMemory
;
1070 pI830
->StolenPool
.Total
= pI830
->StolenMemory
;
1071 pI830
->StolenPool
.Free
= pI830
->StolenPool
.Total
;
1072 pI830
->FreeMemory
= pI830
->StolenPool
.Total
.Size
;
1074 if (!AgpInit(ctx
, pI830
))
1077 if (I830AllocateMemory(ctx
, pI830
) == FALSE
)
1082 if (I830BindMemory(ctx
, pI830
) == FALSE
)
1087 pSAREAPriv
->front_offset
= pI830
->FrontBuffer
.Start
;
1088 pSAREAPriv
->front_size
= pI830
->FrontBuffer
.Size
;
1089 pSAREAPriv
->width
= ctx
->shared
.virtualWidth
;
1090 pSAREAPriv
->height
= ctx
->shared
.virtualHeight
;
1091 pSAREAPriv
->pitch
= ctx
->shared
.virtualWidth
;
1092 pSAREAPriv
->virtualX
= ctx
->shared
.virtualWidth
;
1093 pSAREAPriv
->virtualY
= ctx
->shared
.virtualHeight
;
1094 pSAREAPriv
->back_offset
= pI830
->BackBuffer
.Start
;
1095 pSAREAPriv
->back_size
= pI830
->BackBuffer
.Size
;
1096 pSAREAPriv
->depth_offset
= pI830
->DepthBuffer
.Start
;
1097 pSAREAPriv
->depth_size
= pI830
->DepthBuffer
.Size
;
1098 pSAREAPriv
->tex_offset
= pI830
->TexMem
.Start
;
1099 pSAREAPriv
->tex_size
= pI830
->TexMem
.Size
;
1100 pSAREAPriv
->log_tex_granularity
= pI830
->TexGranularity
;
1102 ctx
->driverClientMsg
= malloc(sizeof(I830DRIRec
));
1103 ctx
->driverClientMsgSize
= sizeof(I830DRIRec
);
1104 pI830DRI
= (I830DRIPtr
)ctx
->driverClientMsg
;
1105 pI830DRI
->deviceID
= pI830
->Chipset
;
1106 pI830DRI
->regsSize
= I830_REG_SIZE
;
1107 pI830DRI
->width
= ctx
->shared
.virtualWidth
;
1108 pI830DRI
->height
= ctx
->shared
.virtualHeight
;
1109 pI830DRI
->mem
= ctx
->shared
.fbSize
;
1110 pI830DRI
->cpp
= ctx
->cpp
;
1111 pI830DRI
->backOffset
= pI830
->BackBuffer
.Start
;
1112 pI830DRI
->backPitch
= pI830
->BackBuffer
.Pitch
;
1114 pI830DRI
->depthOffset
= pI830
->DepthBuffer
.Start
;
1115 pI830DRI
->depthPitch
= pI830
->DepthBuffer
.Pitch
;
1117 pI830DRI
->fbOffset
= pI830
->FrontBuffer
.Start
;
1118 pI830DRI
->fbStride
= pI830
->FrontBuffer
.Pitch
;
1120 pI830DRI
->bitsPerPixel
= ctx
->bpp
;
1121 pI830DRI
->sarea_priv_offset
= sizeof(drm_sarea_t
);
1123 err
= I830DRIDoMappings(ctx
, pI830
, pSAREAPriv
);
1127 I830SetupMemoryTiling(ctx
, pI830
);
1129 /* Quick hack to clear the front & back buffers. Could also use
1130 * the clear ioctl to do this, but would need to setup hw state
1133 I830ClearScreen(ctx
, pI830
, pSAREAPriv
);
1135 I830SetRingRegs(ctx
, pI830
);
1142 * \brief Validate the fbdev mode.
1144 * \param ctx display handle.
1146 * \return one on success, or zero on failure.
1148 * Saves some registers and returns 1.
1150 * \sa radeonValidateMode().
1152 static int i830ValidateMode( const DRIDriverContext
*ctx
)
1158 * \brief Examine mode returned by fbdev.
1160 * \param ctx display handle.
1162 * \return one on success, or zero on failure.
1164 * Restores registers that fbdev has clobbered and returns 1.
1166 * \sa i810ValidateMode().
1168 static int i830PostValidateMode( const DRIDriverContext
*ctx
)
1170 I830Rec
*pI830
= ctx
->driverPrivate
;
1172 I830SetRingRegs(ctx
, pI830
);
1178 * \brief Initialize the framebuffer device mode
1180 * \param ctx display handle.
1182 * \return one on success, or zero on failure.
1184 * Fills in \p info with some default values and some information from \p ctx
1185 * and then calls I810ScreenInit() for the screen initialization.
1187 * Before exiting clears the framebuffer memory accessing it directly.
1189 static int i830InitFBDev( DRIDriverContext
*ctx
)
1191 I830Rec
*pI830
= calloc(1, sizeof(I830Rec
));
1195 int dummy
= ctx
->shared
.virtualWidth
;
1197 switch (ctx
->bpp
/ 8) {
1198 case 1: dummy
= (ctx
->shared
.virtualWidth
+ 127) & ~127; break;
1199 case 2: dummy
= (ctx
->shared
.virtualWidth
+ 31) & ~31; break;
1201 case 4: dummy
= (ctx
->shared
.virtualWidth
+ 15) & ~15; break;
1204 ctx
->shared
.virtualWidth
= dummy
;
1205 ctx
->shared
.Width
= ctx
->shared
.virtualWidth
;
1209 for (i
= 0; pitches
[i
] != 0; i
++) {
1210 if (pitches
[i
] >= ctx
->shared
.virtualWidth
) {
1211 ctx
->shared
.virtualWidth
= pitches
[i
];
1216 ctx
->driverPrivate
= (void *)pI830
;
1218 pI830
->LpRing
= calloc(1, sizeof(I830RingBuffer
));
1219 pI830
->Chipset
= ctx
->chipset
;
1220 pI830
->LinearAddr
= ctx
->FBStart
;
1222 if (!I830ScreenInit( ctx
, pI830
))
1231 * \brief The screen is being closed, so clean up any state and free any
1232 * resources used by the DRI.
1234 * \param ctx display handle.
1236 * Unmaps the SAREA, closes the DRM device file descriptor and frees the driver
1239 static void i830HaltFBDev( DRIDriverContext
*ctx
)
1241 drmI830Sarea
*pSAREAPriv
;
1242 I830Rec
*pI830
= ctx
->driverPrivate
;
1245 drmCtlUninstHandler(ctx
->drmFD
);
1248 I830CleanupDma(ctx
);
1250 pSAREAPriv
= (drmI830Sarea
*)(((char*)ctx
->pSAREA
) +
1251 sizeof(drm_sarea_t
));
1253 I830DRIUnmapScreenRegions(ctx
, pI830
, pSAREAPriv
);
1254 drmUnmap( ctx
->pSAREA
, ctx
->shared
.SAREASize
);
1255 drmClose(ctx
->drmFD
);
1257 if (ctx
->driverPrivate
) {
1258 free(ctx
->driverPrivate
);
1259 ctx
->driverPrivate
= 0;
1264 extern void i810NotifyFocus( int );
1267 * \brief Exported driver interface for Mini GLX.
1271 const struct DRIDriverRec __driDriver
= {
1273 i830PostValidateMode
,
1276 NULL
,//I830EngineShutdown,
1277 NULL
, //I830EngineRestore,