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
, I830MemRange
*result
, I830MemPool
*pool
, long size
, unsigned long alignment
, int flags
)
465 /* Make sure these are initialised. */
473 if (pool
->Free
.Size
< size
)
474 return AllocFromAGP(ctx
, pI830
, size
, alignment
, result
);
477 ret
= AllocFromPool(ctx
, pI830
, result
, pool
, size
, alignment
, flags
);
480 return AllocFromAGP(ctx
, pI830
, size
, alignment
, result
);
485 static Bool
BindAgpRange(const DRIDriverContext
*ctx
, I830MemRange
*mem
)
493 return !drmAgpBind(ctx
->drmFD
, mem
->Key
, mem
->Offset
);
496 /* simple memory allocation routines needed */
497 /* put ring buffer in low memory */
498 /* need to allocate front, back, depth buffers aligned correctly,
499 allocate ring buffer,
504 I830AllocateMemory(const DRIDriverContext
*ctx
, I830Rec
*pI830
)
506 unsigned long size
, ret
;
507 unsigned long lines
, lineSize
, align
;
509 /* allocate ring buffer */
510 memset(pI830
->LpRing
, 0, sizeof(I830RingBuffer
));
511 pI830
->LpRing
->mem
.Key
= -1;
513 size
= PRIMARY_RINGBUFFER_SIZE
;
515 ret
= I830AllocVidMem(ctx
, pI830
, &pI830
->LpRing
->mem
, &pI830
->StolenPool
, size
, 0x1000, 0);
519 fprintf(stderr
,"unable to allocate ring buffer %ld\n", ret
);
523 pI830
->LpRing
->tail_mask
= pI830
->LpRing
->mem
.Size
- 1;
526 /* allocate front buffer */
527 memset(&(pI830
->FrontBuffer
), 0, sizeof(pI830
->FrontBuffer
));
528 pI830
->FrontBuffer
.Key
= -1;
529 pI830
->FrontBuffer
.Pitch
= ctx
->shared
.virtualWidth
;
533 lineSize
= ctx
->shared
.virtualWidth
* ctx
->cpp
;
534 lines
= (ctx
->shared
.virtualHeight
+ 15) / 16 * 16;
535 size
= lineSize
* lines
;
536 size
= ROUND_TO_PAGE(size
);
538 align
= GetBestTileAlignment(size
);
540 ret
= I830AllocVidMem(ctx
, pI830
, &pI830
->FrontBuffer
, &pI830
->StolenPool
, size
, align
, 0);
543 fprintf(stderr
,"unable to allocate front buffer %ld\n", ret
);
547 memset(&(pI830
->BackBuffer
), 0, sizeof(pI830
->BackBuffer
));
548 pI830
->BackBuffer
.Key
= -1;
549 pI830
->BackBuffer
.Pitch
= ctx
->shared
.virtualWidth
;
551 ret
= I830AllocVidMem(ctx
, pI830
, &pI830
->BackBuffer
, &pI830
->StolenPool
, size
, align
, 0);
554 fprintf(stderr
,"unable to allocate back buffer %ld\n", ret
);
558 memset(&(pI830
->DepthBuffer
), 0, sizeof(pI830
->DepthBuffer
));
559 pI830
->DepthBuffer
.Key
= -1;
560 pI830
->DepthBuffer
.Pitch
= ctx
->shared
.virtualWidth
;
562 ret
= I830AllocVidMem(ctx
, pI830
, &pI830
->DepthBuffer
, &pI830
->StolenPool
, size
, align
, 0);
565 fprintf(stderr
,"unable to allocate depth buffer %ld\n", ret
);
569 memset(&(pI830
->ContextMem
), 0, sizeof(pI830
->ContextMem
));
570 pI830
->ContextMem
.Key
= -1;
573 ret
= I830AllocVidMem(ctx
, pI830
, &pI830
->ContextMem
, &pI830
->StolenPool
, size
, align
, 0);
576 fprintf(stderr
,"unable to allocate context buffer %ld\n", ret
);
580 memset(&(pI830
->TexMem
), 0, sizeof(pI830
->TexMem
));
581 pI830
->TexMem
.Key
= -1;
584 ret
= AllocFromAGP(ctx
, pI830
, size
, align
, &pI830
->TexMem
);
587 fprintf(stderr
,"unable to allocate texture memory %ld\n", ret
);
595 I830BindMemory(const DRIDriverContext
*ctx
, I830Rec
*pI830
)
597 if (!BindAgpRange(ctx
, &pI830
->LpRing
->mem
))
599 if (!BindAgpRange(ctx
, &pI830
->FrontBuffer
))
601 if (!BindAgpRange(ctx
, &pI830
->BackBuffer
))
603 if (!BindAgpRange(ctx
, &pI830
->DepthBuffer
))
605 if (!BindAgpRange(ctx
, &pI830
->ContextMem
))
607 if (!BindAgpRange(ctx
, &pI830
->TexMem
))
614 I830CleanupDma(const DRIDriverContext
*ctx
)
618 memset(&info
, 0, sizeof(drmI830Init
));
619 info
.func
= I830_CLEANUP_DMA
;
621 if (drmCommandWrite(ctx
->drmFD
, DRM_I830_INIT
,
622 &info
, sizeof(drmI830Init
))) {
623 fprintf(stderr
, "I830 Dma Cleanup Failed\n");
631 I830InitDma(const DRIDriverContext
*ctx
, I830Rec
*pI830
)
633 I830RingBuffer
*ring
= pI830
->LpRing
;
636 memset(&info
, 0, sizeof(drmI830Init
));
637 info
.func
= I830_INIT_DMA
;
639 info
.ring_start
= ring
->mem
.Start
+ pI830
->LinearAddr
;
640 info
.ring_end
= ring
->mem
.End
+ pI830
->LinearAddr
;
641 info
.ring_size
= ring
->mem
.Size
;
643 info
.mmio_offset
= (unsigned int)ctx
->MMIOStart
;
645 info
.sarea_priv_offset
= sizeof(drm_sarea_t
);
647 info
.front_offset
= pI830
->FrontBuffer
.Start
;
648 info
.back_offset
= pI830
->BackBuffer
.Start
;
649 info
.depth_offset
= pI830
->DepthBuffer
.Start
;
650 info
.w
= ctx
->shared
.virtualWidth
;
651 info
.h
= ctx
->shared
.virtualHeight
;
652 info
.pitch
= ctx
->shared
.virtualWidth
;
653 info
.back_pitch
= pI830
->BackBuffer
.Pitch
;
654 info
.depth_pitch
= pI830
->DepthBuffer
.Pitch
;
657 if (drmCommandWrite(ctx
->drmFD
, DRM_I830_INIT
,
658 &info
, sizeof(drmI830Init
))) {
660 "I830 Dma Initialization Failed\n");
667 static int I830CheckDRMVersion( const DRIDriverContext
*ctx
,
670 drmVersionPtr version
;
672 version
= drmGetVersion(ctx
->drmFD
);
675 int req_minor
, req_patch
;
680 if (version
->version_major
!= 1 ||
681 version
->version_minor
< req_minor
||
682 (version
->version_minor
== req_minor
&&
683 version
->version_patchlevel
< req_patch
)) {
684 /* Incompatible drm version */
686 "[dri] I830DRIScreenInit failed because of a version "
688 "[dri] i915.o kernel module version is %d.%d.%d "
689 "but version 1.%d.%d or newer is needed.\n"
690 "[dri] Disabling DRI.\n",
691 version
->version_major
,
692 version
->version_minor
,
693 version
->version_patchlevel
,
696 drmFreeVersion(version
);
700 pI830
->drmMinor
= version
->version_minor
;
701 drmFreeVersion(version
);
707 I830SetRingRegs(const DRIDriverContext
*ctx
, I830Rec
*pI830
)
710 unsigned char *MMIO
= ctx
->MMIOAddress
;
712 OUTREG(LP_RING
+ RING_LEN
, 0);
713 OUTREG(LP_RING
+ RING_TAIL
, 0);
714 OUTREG(LP_RING
+ RING_HEAD
, 0);
716 if ((long)(pI830
->LpRing
->mem
.Start
& I830_RING_START_MASK
) !=
717 pI830
->LpRing
->mem
.Start
) {
719 "I830SetRingRegs: Ring buffer start (%lx) violates its "
720 "mask (%x)\n", pI830
->LpRing
->mem
.Start
, I830_RING_START_MASK
);
722 /* Don't care about the old value. Reserved bits must be zero anyway. */
723 itemp
= pI830
->LpRing
->mem
.Start
& I830_RING_START_MASK
;
724 OUTREG(LP_RING
+ RING_START
, itemp
);
726 if (((pI830
->LpRing
->mem
.Size
- 4096) & I830_RING_NR_PAGES
) !=
727 pI830
->LpRing
->mem
.Size
- 4096) {
729 "I830SetRingRegs: Ring buffer size - 4096 (%lx) violates its "
730 "mask (%x)\n", pI830
->LpRing
->mem
.Size
- 4096,
733 /* Don't care about the old value. Reserved bits must be zero anyway. */
734 itemp
= (pI830
->LpRing
->mem
.Size
- 4096) & I830_RING_NR_PAGES
;
735 itemp
|= (RING_NO_REPORT
| RING_VALID
);
736 OUTREG(LP_RING
+ RING_LEN
, itemp
);
738 pI830
->LpRing
->head
= INREG(LP_RING
+ RING_HEAD
) & I830_HEAD_MASK
;
739 pI830
->LpRing
->tail
= INREG(LP_RING
+ RING_TAIL
);
740 pI830
->LpRing
->space
= pI830
->LpRing
->head
- (pI830
->LpRing
->tail
+ 8);
741 if (pI830
->LpRing
->space
< 0)
742 pI830
->LpRing
->space
+= pI830
->LpRing
->mem
.Size
;
744 SetFenceRegs(ctx
, pI830
);
746 /* RESET THE DISPLAY PIPE TO POINT TO THE FRONTBUFFER - hacky
748 OUTREG(DSPABASE
, pI830
->FrontBuffer
.Start
+ pI830
->LinearAddr
);
753 I830SetParam(const DRIDriverContext
*ctx
, int param
, int value
)
757 memset(&sp
, 0, sizeof(sp
));
761 if (drmCommandWrite(ctx
->drmFD
, DRM_I830_SETPARAM
, &sp
, sizeof(sp
))) {
762 fprintf(stderr
, "I830 SetParam Failed\n");
770 I830DRIMapScreenRegions(DRIDriverContext
*ctx
, I830Rec
*pI830
, drmI830Sarea
*sarea
)
773 "[drm] Mapping front buffer\n");
775 if (drmAddMap(ctx
->drmFD
,
776 (drm_handle_t
)(sarea
->front_offset
+ pI830
->LinearAddr
),
778 DRM_FRAME_BUFFER
, /*DRM_AGP,*/
780 &sarea
->front_handle
) < 0) {
782 "[drm] drmAddMap(front_handle) failed. Disabling DRI\n");
785 ctx
->shared
.hFrameBuffer
= sarea
->front_handle
;
786 ctx
->shared
.fbSize
= sarea
->front_size
;
787 fprintf(stderr
, "[drm] Front Buffer = 0x%08x\n",
788 sarea
->front_handle
);
790 if (drmAddMap(ctx
->drmFD
,
791 (drm_handle_t
)(sarea
->back_offset
),
792 sarea
->back_size
, DRM_AGP
, 0,
793 &sarea
->back_handle
) < 0) {
795 "[drm] drmAddMap(back_handle) failed. Disabling DRI\n");
798 fprintf(stderr
, "[drm] Back Buffer = 0x%08x\n",
801 if (drmAddMap(ctx
->drmFD
,
802 (drm_handle_t
)sarea
->depth_offset
,
803 sarea
->depth_size
, DRM_AGP
, 0,
804 &sarea
->depth_handle
) < 0) {
806 "[drm] drmAddMap(depth_handle) failed. Disabling DRI\n");
809 fprintf(stderr
, "[drm] Depth Buffer = 0x%08x\n",
810 sarea
->depth_handle
);
812 if (drmAddMap(ctx
->drmFD
,
813 (drm_handle_t
)sarea
->tex_offset
,
814 sarea
->tex_size
, DRM_AGP
, 0,
815 &sarea
->tex_handle
) < 0) {
817 "[drm] drmAddMap(tex_handle) failed. Disabling DRI\n");
820 fprintf(stderr
, "[drm] textures = 0x%08x\n",
828 I830DRIUnmapScreenRegions(const DRIDriverContext
*ctx
, I830Rec
*pI830
, drmI830Sarea
*sarea
)
831 if (sarea
->front_handle
) {
832 drmRmMap(ctx
->drmFD
, sarea
->front_handle
);
833 sarea
->front_handle
= 0;
836 if (sarea
->back_handle
) {
837 drmRmMap(ctx
->drmFD
, sarea
->back_handle
);
838 sarea
->back_handle
= 0;
840 if (sarea
->depth_handle
) {
841 drmRmMap(ctx
->drmFD
, sarea
->depth_handle
);
842 sarea
->depth_handle
= 0;
844 if (sarea
->tex_handle
) {
845 drmRmMap(ctx
->drmFD
, sarea
->tex_handle
);
846 sarea
->tex_handle
= 0;
851 I830InitTextureHeap(const DRIDriverContext
*ctx
, I830Rec
*pI830
, drmI830Sarea
*sarea
)
853 /* Start up the simple memory manager for agp space */
854 drmI830MemInitHeap drmHeap
;
855 drmHeap
.region
= I830_MEM_REGION_AGP
;
857 drmHeap
.size
= sarea
->tex_size
;
859 if (drmCommandWrite(ctx
->drmFD
, DRM_I830_INIT_HEAP
,
860 &drmHeap
, sizeof(drmHeap
))) {
862 "[drm] Failed to initialized agp heap manager\n");
865 "[drm] Initialized kernel agp heap manager, %d\n",
868 I830SetParam(ctx
, I830_SETPARAM_TEX_LRU_LOG_GRANULARITY
,
869 sarea
->log_tex_granularity
);
874 I830DRIDoMappings(DRIDriverContext
*ctx
, I830Rec
*pI830
, drmI830Sarea
*sarea
)
876 if (drmAddMap(ctx
->drmFD
,
877 (drm_handle_t
)pI830
->LpRing
->mem
.Start
,
878 pI830
->LpRing
->mem
.Size
, DRM_AGP
, 0,
879 &pI830
->ring_map
) < 0) {
881 "[drm] drmAddMap(ring_map) failed. Disabling DRI\n");
884 fprintf(stderr
, "[drm] ring buffer = 0x%08x\n",
887 if (I830InitDma(ctx
, pI830
) == FALSE
) {
891 /* init to zero to be safe */
893 I830DRIMapScreenRegions(ctx
, pI830
, sarea
);
894 I830InitTextureHeap(ctx
, pI830
, sarea
);
896 if (ctx
->pciDevice
!= PCI_CHIP_845_G
&&
897 ctx
->pciDevice
!= PCI_CHIP_I830_M
) {
898 I830SetParam(ctx
, I830_SETPARAM_USE_MI_BATCHBUFFER_START
, 1 );
901 /* Okay now initialize the dma engine */
903 pI830
->irq
= drmGetInterruptFromBusID(ctx
->drmFD
,
908 if (drmCtlInstHandler(ctx
->drmFD
, pI830
->irq
)) {
910 "[drm] failure adding irq handler\n");
916 "[drm] dma control initialized, using IRQ %d\n",
920 fprintf(stderr
, "[dri] visual configs initialized\n");
926 I830ClearScreen(DRIDriverContext
*ctx
, I830Rec
*pI830
, drmI830Sarea
*sarea
)
928 /* need to drmMap front and back buffers and zero them */
932 ret
= drmMap(ctx
->drmFD
,
939 fprintf(stderr
, "Unable to map front buffer\n");
943 drimemsetio((char *)map_addr
,
946 drmUnmap(map_addr
, sarea
->front_size
);
949 ret
= drmMap(ctx
->drmFD
,
956 fprintf(stderr
, "Unable to map back buffer\n");
960 drimemsetio((char *)map_addr
,
963 drmUnmap(map_addr
, sarea
->back_size
);
969 I830ScreenInit(DRIDriverContext
*ctx
, I830Rec
*pI830
)
973 drmI830Sarea
*pSAREAPriv
;
976 drm_page_size
= getpagesize();
978 pI830
->registerSize
= ctx
->MMIOSize
;
979 /* This is a hack for now. We have to have more than a 4k page here
980 * because of the size of the state. However, the state should be
981 * in a per-context mapping. This will be added in the Mesa 3.5 port
982 * of the I830 driver.
984 ctx
->shared
.SAREASize
= SAREA_MAX
;
986 /* Note that drmOpen will try to load the kernel module, if needed. */
987 ctx
->drmFD
= drmOpen("i915", NULL
);
988 if (ctx
->drmFD
< 0) {
989 fprintf(stderr
, "[drm] drmOpen failed\n");
993 if ((err
= drmSetBusid(ctx
->drmFD
, ctx
->pciBusID
)) < 0) {
994 fprintf(stderr
, "[drm] drmSetBusid failed (%d, %s), %s\n",
995 ctx
->drmFD
, ctx
->pciBusID
, strerror(-err
));
999 if (drmAddMap( ctx
->drmFD
,
1001 ctx
->shared
.SAREASize
,
1004 &ctx
->shared
.hSAREA
) < 0)
1006 fprintf(stderr
, "[drm] drmAddMap failed\n");
1010 fprintf(stderr
, "[drm] added %d byte SAREA at 0x%08x\n",
1011 ctx
->shared
.SAREASize
, ctx
->shared
.hSAREA
);
1013 if (drmMap( ctx
->drmFD
,
1015 ctx
->shared
.SAREASize
,
1016 (drmAddressPtr
)(&ctx
->pSAREA
)) < 0)
1018 fprintf(stderr
, "[drm] drmMap failed\n");
1023 memset(ctx
->pSAREA
, 0, ctx
->shared
.SAREASize
);
1024 fprintf(stderr
, "[drm] mapped SAREA 0x%08x to %p, size %d\n",
1025 ctx
->shared
.hSAREA
, ctx
->pSAREA
, ctx
->shared
.SAREASize
);
1028 if (drmAddMap(ctx
->drmFD
,
1033 &pI830
->registerHandle
) < 0) {
1034 fprintf(stderr
, "[drm] drmAddMap mmio failed\n");
1038 "[drm] register handle = 0x%08x\n", pI830
->registerHandle
);
1041 if (!I830CheckDRMVersion(ctx
, pI830
)) {
1045 /* Create a 'server' context so we can grab the lock for
1046 * initialization ioctls.
1048 if ((err
= drmCreateContext(ctx
->drmFD
, &ctx
->serverContext
)) != 0) {
1049 fprintf(stderr
, "%s: drmCreateContext failed %d\n", __FUNCTION__
, err
);
1053 DRM_LOCK(ctx
->drmFD
, ctx
->pSAREA
, ctx
->serverContext
, 0);
1055 /* Initialize the SAREA private data structure */
1056 pSAREAPriv
= (drmI830Sarea
*)(((char*)ctx
->pSAREA
) +
1057 sizeof(drm_sarea_t
));
1058 memset(pSAREAPriv
, 0, sizeof(*pSAREAPriv
));
1060 pI830
->StolenMemory
.Size
= I830DetectMemory(ctx
, pI830
);
1061 pI830
->StolenMemory
.Start
= 0;
1062 pI830
->StolenMemory
.End
= pI830
->StolenMemory
.Size
;
1064 pI830
->MemoryAperture
.Start
= pI830
->StolenMemory
.End
;
1065 pI830
->MemoryAperture
.End
= KB(40000);
1066 pI830
->MemoryAperture
.Size
= pI830
->MemoryAperture
.End
- pI830
->MemoryAperture
.Start
;
1068 pI830
->StolenPool
.Fixed
= pI830
->StolenMemory
;
1069 pI830
->StolenPool
.Total
= pI830
->StolenMemory
;
1070 pI830
->StolenPool
.Free
= pI830
->StolenPool
.Total
;
1071 pI830
->FreeMemory
= pI830
->StolenPool
.Total
.Size
;
1073 if (!AgpInit(ctx
, pI830
))
1076 if (I830AllocateMemory(ctx
, pI830
) == FALSE
)
1081 if (I830BindMemory(ctx
, pI830
) == FALSE
)
1086 pSAREAPriv
->front_offset
= pI830
->FrontBuffer
.Start
;
1087 pSAREAPriv
->front_size
= pI830
->FrontBuffer
.Size
;
1088 pSAREAPriv
->width
= ctx
->shared
.virtualWidth
;
1089 pSAREAPriv
->height
= ctx
->shared
.virtualHeight
;
1090 pSAREAPriv
->pitch
= ctx
->shared
.virtualWidth
;
1091 pSAREAPriv
->virtualX
= ctx
->shared
.virtualWidth
;
1092 pSAREAPriv
->virtualY
= ctx
->shared
.virtualHeight
;
1093 pSAREAPriv
->back_offset
= pI830
->BackBuffer
.Start
;
1094 pSAREAPriv
->back_size
= pI830
->BackBuffer
.Size
;
1095 pSAREAPriv
->depth_offset
= pI830
->DepthBuffer
.Start
;
1096 pSAREAPriv
->depth_size
= pI830
->DepthBuffer
.Size
;
1097 pSAREAPriv
->tex_offset
= pI830
->TexMem
.Start
;
1098 pSAREAPriv
->tex_size
= pI830
->TexMem
.Size
;
1099 pSAREAPriv
->log_tex_granularity
= pI830
->TexGranularity
;
1101 ctx
->driverClientMsg
= malloc(sizeof(I830DRIRec
));
1102 ctx
->driverClientMsgSize
= sizeof(I830DRIRec
);
1103 pI830DRI
= (I830DRIPtr
)ctx
->driverClientMsg
;
1104 pI830DRI
->deviceID
= pI830
->Chipset
;
1105 pI830DRI
->regsSize
= I830_REG_SIZE
;
1106 pI830DRI
->width
= ctx
->shared
.virtualWidth
;
1107 pI830DRI
->height
= ctx
->shared
.virtualHeight
;
1108 pI830DRI
->mem
= ctx
->shared
.fbSize
;
1109 pI830DRI
->cpp
= ctx
->cpp
;
1110 pI830DRI
->backOffset
= pI830
->BackBuffer
.Start
;
1111 pI830DRI
->backPitch
= pI830
->BackBuffer
.Pitch
;
1113 pI830DRI
->depthOffset
= pI830
->DepthBuffer
.Start
;
1114 pI830DRI
->depthPitch
= pI830
->DepthBuffer
.Pitch
;
1116 pI830DRI
->fbOffset
= pI830
->FrontBuffer
.Start
;
1117 pI830DRI
->fbStride
= pI830
->FrontBuffer
.Pitch
;
1119 pI830DRI
->bitsPerPixel
= ctx
->bpp
;
1120 pI830DRI
->sarea_priv_offset
= sizeof(drm_sarea_t
);
1122 err
= I830DRIDoMappings(ctx
, pI830
, pSAREAPriv
);
1126 I830SetupMemoryTiling(ctx
, pI830
);
1128 /* Quick hack to clear the front & back buffers. Could also use
1129 * the clear ioctl to do this, but would need to setup hw state
1132 I830ClearScreen(ctx
, pI830
, pSAREAPriv
);
1134 I830SetRingRegs(ctx
, pI830
);
1141 * \brief Validate the fbdev mode.
1143 * \param ctx display handle.
1145 * \return one on success, or zero on failure.
1147 * Saves some registers and returns 1.
1149 * \sa radeonValidateMode().
1151 static int i830ValidateMode( const DRIDriverContext
*ctx
)
1157 * \brief Examine mode returned by fbdev.
1159 * \param ctx display handle.
1161 * \return one on success, or zero on failure.
1163 * Restores registers that fbdev has clobbered and returns 1.
1165 * \sa i810ValidateMode().
1167 static int i830PostValidateMode( const DRIDriverContext
*ctx
)
1169 I830Rec
*pI830
= ctx
->driverPrivate
;
1171 I830SetRingRegs(ctx
, pI830
);
1177 * \brief Initialize the framebuffer device mode
1179 * \param ctx display handle.
1181 * \return one on success, or zero on failure.
1183 * Fills in \p info with some default values and some information from \p ctx
1184 * and then calls I810ScreenInit() for the screen initialization.
1186 * Before exiting clears the framebuffer memory accessing it directly.
1188 static int i830InitFBDev( DRIDriverContext
*ctx
)
1190 I830Rec
*pI830
= calloc(1, sizeof(I830Rec
));
1194 int dummy
= ctx
->shared
.virtualWidth
;
1196 switch (ctx
->bpp
/ 8) {
1197 case 1: dummy
= (ctx
->shared
.virtualWidth
+ 127) & ~127; break;
1198 case 2: dummy
= (ctx
->shared
.virtualWidth
+ 31) & ~31; break;
1200 case 4: dummy
= (ctx
->shared
.virtualWidth
+ 15) & ~15; break;
1203 ctx
->shared
.virtualWidth
= dummy
;
1204 ctx
->shared
.Width
= ctx
->shared
.virtualWidth
;
1208 for (i
= 0; pitches
[i
] != 0; i
++) {
1209 if (pitches
[i
] >= ctx
->shared
.virtualWidth
) {
1210 ctx
->shared
.virtualWidth
= pitches
[i
];
1215 ctx
->driverPrivate
= (void *)pI830
;
1217 pI830
->LpRing
= calloc(1, sizeof(I830RingBuffer
));
1218 pI830
->Chipset
= ctx
->chipset
;
1219 pI830
->LinearAddr
= ctx
->FBStart
;
1221 if (!I830ScreenInit( ctx
, pI830
))
1230 * \brief The screen is being closed, so clean up any state and free any
1231 * resources used by the DRI.
1233 * \param ctx display handle.
1235 * Unmaps the SAREA, closes the DRM device file descriptor and frees the driver
1238 static void i830HaltFBDev( DRIDriverContext
*ctx
)
1240 drmI830Sarea
*pSAREAPriv
;
1241 I830Rec
*pI830
= ctx
->driverPrivate
;
1244 drmCtlUninstHandler(ctx
->drmFD
);
1247 I830CleanupDma(ctx
);
1249 pSAREAPriv
= (drmI830Sarea
*)(((char*)ctx
->pSAREA
) +
1250 sizeof(drm_sarea_t
));
1252 I830DRIUnmapScreenRegions(ctx
, pI830
, pSAREAPriv
);
1253 drmUnmap( ctx
->pSAREA
, ctx
->shared
.SAREASize
);
1254 drmClose(ctx
->drmFD
);
1256 if (ctx
->driverPrivate
) {
1257 free(ctx
->driverPrivate
);
1258 ctx
->driverPrivate
= 0;
1263 extern void i810NotifyFocus( int );
1266 * \brief Exported driver interface for Mini GLX.
1270 const struct DRIDriverRec __driDriver
= {
1272 i830PostValidateMode
,
1275 NULL
,//I830EngineShutdown,
1276 NULL
, //I830EngineRestore,