Merge branch 'master' into i915-unification
[mesa.git] / src / mesa / drivers / dri / i915 / 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;
296 uint32_t gmch_ctrl;
297 int memsize = 0;
298 int range;
299
300 memset(&host_bridge, 0, sizeof(host_bridge));
301
302 pci_device_cfg_read_u32(&host_bridge, &gmch_ctrl, I830_GMCH_CTRL);
303
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;
307
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);
312 break;
313 case I855_GMCH_GMS_STOLEN_4M:
314 memsize = MB(4) - KB(range);
315 break;
316 case I855_GMCH_GMS_STOLEN_8M:
317 memsize = MB(8) - KB(range);
318 break;
319 case I855_GMCH_GMS_STOLEN_16M:
320 memsize = MB(16) - KB(range);
321 break;
322 case I855_GMCH_GMS_STOLEN_32M:
323 memsize = MB(32) - KB(range);
324 break;
325 case I915G_GMCH_GMS_STOLEN_48M:
326 if (IS_I9XX(pI830))
327 memsize = MB(48) - KB(range);
328 break;
329 case I915G_GMCH_GMS_STOLEN_64M:
330 if (IS_I9XX(pI830))
331 memsize = MB(64) - KB(range);
332 break;
333 }
334 } else {
335 switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
336 case I830_GMCH_GMS_STOLEN_512:
337 memsize = KB(512) - KB(range);
338 break;
339 case I830_GMCH_GMS_STOLEN_1024:
340 memsize = MB(1) - KB(range);
341 break;
342 case I830_GMCH_GMS_STOLEN_8192:
343 memsize = MB(8) - KB(range);
344 break;
345 case I830_GMCH_GMS_LOCAL:
346 memsize = 0;
347 xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
348 "Local memory found, but won't be used.\n");
349 break;
350 }
351 }
352 if (memsize > 0) {
353 fprintf(stderr,
354 "detected %d kB stolen memory.\n", memsize / 1024);
355 } else {
356 fprintf(stderr,
357 "no video memory detected.\n");
358 }
359 return memsize;
360 }
361
362 static int AgpInit(const DRIDriverContext *ctx, I830Rec *info)
363 {
364 unsigned long mode = 0x4;
365
366 if (drmAgpAcquire(ctx->drmFD) < 0) {
367 fprintf(stderr, "[gart] AGP not available\n");
368 return 0;
369 }
370
371 if (drmAgpEnable(ctx->drmFD, mode) < 0) {
372 fprintf(stderr, "[gart] AGP not enabled\n");
373 drmAgpRelease(ctx->drmFD);
374 return 0;
375 }
376 else
377 fprintf(stderr, "[gart] AGP enabled at %dx\n", ctx->agpmode);
378
379 return 1;
380 }
381
382 /*
383 * Allocate memory from the given pool. Grow the pool if needed and if
384 * possible.
385 */
386 static unsigned long
387 AllocFromPool(const DRIDriverContext *ctx, I830Rec *pI830,
388 I830MemRange *result, I830MemPool *pool,
389 long size, unsigned long alignment, int flags)
390 {
391 long needed, start, end;
392
393 if (!result || !pool || !size)
394 return 0;
395
396 /* Calculate how much space is needed. */
397 if (alignment <= GTT_PAGE_SIZE)
398 needed = size;
399 else {
400 start = ROUND_TO(pool->Free.Start, alignment);
401 end = ROUND_TO(start + size, alignment);
402 needed = end - pool->Free.Start;
403 }
404 if (needed > pool->Free.Size) {
405 return 0;
406 }
407
408 result->Start = ROUND_TO(pool->Free.Start, alignment);
409 pool->Free.Start += needed;
410 result->End = pool->Free.Start;
411
412 pool->Free.Size = pool->Free.End - pool->Free.Start;
413 result->Size = result->End - result->Start;
414 result->Pool = pool;
415 result->Alignment = alignment;
416 return needed;
417 }
418
419 static unsigned long AllocFromAGP(const DRIDriverContext *ctx, I830Rec *pI830, long size, unsigned long alignment, I830MemRange *result)
420 {
421 unsigned long start, end;
422 unsigned long newApStart, newApEnd;
423 int ret;
424 if (!result || !size)
425 return 0;
426
427 if (!alignment)
428 alignment = 4;
429
430 start = ROUND_TO(pI830->MemoryAperture.Start, alignment);
431 end = ROUND_TO(start + size, alignment);
432 newApStart = end;
433 newApEnd = pI830->MemoryAperture.End;
434
435 ret=drmAgpAlloc(ctx->drmFD, size, 0, &(result->Physical), (drm_handle_t *)&(result->Key));
436
437 if (ret)
438 {
439 fprintf(stderr,"drmAgpAlloc failed %d\n", ret);
440 return 0;
441 }
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;
449 result->Size = size;
450 result->Offset = start;
451 result->Alignment = alignment;
452 result->Pool = NULL;
453
454 return size;
455 }
456
457 unsigned long
458 I830AllocVidMem(const DRIDriverContext *ctx, I830Rec *pI830,
459 I830MemRange *result, I830MemPool *pool, long size,
460 unsigned long alignment, int flags)
461 {
462 unsigned long ret;
463
464 if (!result)
465 return 0;
466
467 /* Make sure these are initialised. */
468 result->Size = 0;
469 result->Key = -1;
470
471 if (!size) {
472 return 0;
473 }
474
475 if (pool->Free.Size < size) {
476 ret = AllocFromAGP(ctx, pI830, size, alignment, result);
477 }
478 else {
479 ret = AllocFromPool(ctx, pI830, result, pool, size, alignment, flags);
480 if (ret == 0)
481 ret = AllocFromAGP(ctx, pI830, size, alignment, result);
482 }
483 return ret;
484 }
485
486 static Bool BindAgpRange(const DRIDriverContext *ctx, I830MemRange *mem)
487 {
488 if (!mem)
489 return FALSE;
490
491 if (mem->Key == -1)
492 return TRUE;
493
494 return !drmAgpBind(ctx->drmFD, mem->Key, mem->Offset);
495 }
496
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,
501 */
502
503 /* */
504 static Bool
505 I830AllocateMemory(const DRIDriverContext *ctx, I830Rec *pI830)
506 {
507 unsigned long size, ret;
508 unsigned long lines, lineSize, align;
509
510 /* allocate ring buffer */
511 memset(pI830->LpRing, 0, sizeof(I830RingBuffer));
512 pI830->LpRing->mem.Key = -1;
513
514 size = PRIMARY_RINGBUFFER_SIZE;
515
516 ret = I830AllocVidMem(ctx, pI830, &pI830->LpRing->mem, &pI830->StolenPool, size, 0x1000, 0);
517
518 if (ret != size)
519 {
520 fprintf(stderr,"unable to allocate ring buffer %ld\n", ret);
521 return FALSE;
522 }
523
524 pI830->LpRing->tail_mask = pI830->LpRing->mem.Size - 1;
525
526
527 /* allocate front buffer */
528 memset(&(pI830->FrontBuffer), 0, sizeof(pI830->FrontBuffer));
529 pI830->FrontBuffer.Key = -1;
530 pI830->FrontBuffer.Pitch = ctx->shared.virtualWidth;
531
532 align = KB(512);
533
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);
538
539 align = GetBestTileAlignment(size);
540
541 ret = I830AllocVidMem(ctx, pI830, &pI830->FrontBuffer, &pI830->StolenPool, size, align, 0);
542 if (ret < size)
543 {
544 fprintf(stderr,"unable to allocate front buffer %ld\n", ret);
545 return FALSE;
546 }
547
548 memset(&(pI830->BackBuffer), 0, sizeof(pI830->BackBuffer));
549 pI830->BackBuffer.Key = -1;
550 pI830->BackBuffer.Pitch = ctx->shared.virtualWidth;
551
552 ret = I830AllocVidMem(ctx, pI830, &pI830->BackBuffer, &pI830->StolenPool, size, align, 0);
553 if (ret < size)
554 {
555 fprintf(stderr,"unable to allocate back buffer %ld\n", ret);
556 return FALSE;
557 }
558
559 memset(&(pI830->DepthBuffer), 0, sizeof(pI830->DepthBuffer));
560 pI830->DepthBuffer.Key = -1;
561 pI830->DepthBuffer.Pitch = ctx->shared.virtualWidth;
562
563 ret = I830AllocVidMem(ctx, pI830, &pI830->DepthBuffer, &pI830->StolenPool, size, align, 0);
564 if (ret < size)
565 {
566 fprintf(stderr,"unable to allocate depth buffer %ld\n", ret);
567 return FALSE;
568 }
569
570 memset(&(pI830->ContextMem), 0, sizeof(pI830->ContextMem));
571 pI830->ContextMem.Key = -1;
572 size = KB(32);
573
574 ret = I830AllocVidMem(ctx, pI830, &pI830->ContextMem, &pI830->StolenPool, size, align, 0);
575 if (ret < size)
576 {
577 fprintf(stderr,"unable to allocate context buffer %ld\n", ret);
578 return FALSE;
579 }
580
581 memset(&(pI830->TexMem), 0, sizeof(pI830->TexMem));
582 pI830->TexMem.Key = -1;
583
584 size = 32768 * 1024;
585 ret = AllocFromAGP(ctx, pI830, size, align, &pI830->TexMem);
586 if (ret < size)
587 {
588 fprintf(stderr,"unable to allocate texture memory %ld\n", ret);
589 return FALSE;
590 }
591
592 return TRUE;
593 }
594
595 static Bool
596 I830BindMemory(const DRIDriverContext *ctx, I830Rec *pI830)
597 {
598 if (!BindAgpRange(ctx, &pI830->LpRing->mem))
599 return FALSE;
600 if (!BindAgpRange(ctx, &pI830->FrontBuffer))
601 return FALSE;
602 if (!BindAgpRange(ctx, &pI830->BackBuffer))
603 return FALSE;
604 if (!BindAgpRange(ctx, &pI830->DepthBuffer))
605 return FALSE;
606 if (!BindAgpRange(ctx, &pI830->ContextMem))
607 return FALSE;
608 if (!BindAgpRange(ctx, &pI830->TexMem))
609 return FALSE;
610
611 return TRUE;
612 }
613
614 static Bool
615 I830CleanupDma(const DRIDriverContext *ctx)
616 {
617 drmI830Init info;
618
619 memset(&info, 0, sizeof(drmI830Init));
620 info.func = I830_CLEANUP_DMA;
621
622 if (drmCommandWrite(ctx->drmFD, DRM_I830_INIT,
623 &info, sizeof(drmI830Init))) {
624 fprintf(stderr, "I830 Dma Cleanup Failed\n");
625 return FALSE;
626 }
627
628 return TRUE;
629 }
630
631 static Bool
632 I830InitDma(const DRIDriverContext *ctx, I830Rec *pI830)
633 {
634 I830RingBuffer *ring = pI830->LpRing;
635 drmI830Init info;
636
637 memset(&info, 0, sizeof(drmI830Init));
638 info.func = I830_INIT_DMA;
639
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;
643
644 info.mmio_offset = (unsigned int)ctx->MMIOStart;
645
646 info.sarea_priv_offset = sizeof(drm_sarea_t);
647
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;
656 info.cpp = ctx->cpp;
657
658 if (drmCommandWrite(ctx->drmFD, DRM_I830_INIT,
659 &info, sizeof(drmI830Init))) {
660 fprintf(stderr,
661 "I830 Dma Initialization Failed\n");
662 return FALSE;
663 }
664
665 return TRUE;
666 }
667
668 static int I830CheckDRMVersion( const DRIDriverContext *ctx,
669 I830Rec *pI830 )
670 {
671 drmVersionPtr version;
672
673 version = drmGetVersion(ctx->drmFD);
674
675 if (version) {
676 int req_minor, req_patch;
677
678 req_minor = 4;
679 req_patch = 0;
680
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 */
686 fprintf(stderr,
687 "[dri] I830DRIScreenInit failed because of a version "
688 "mismatch.\n"
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,
695 req_minor,
696 req_patch);
697 drmFreeVersion(version);
698 return 0;
699 }
700
701 pI830->drmMinor = version->version_minor;
702 drmFreeVersion(version);
703 }
704 return 1;
705 }
706
707 static void
708 I830SetRingRegs(const DRIDriverContext *ctx, I830Rec *pI830)
709 {
710 unsigned int itemp;
711 unsigned char *MMIO = ctx->MMIOAddress;
712
713 OUTREG(LP_RING + RING_LEN, 0);
714 OUTREG(LP_RING + RING_TAIL, 0);
715 OUTREG(LP_RING + RING_HEAD, 0);
716
717 if ((long)(pI830->LpRing->mem.Start & I830_RING_START_MASK) !=
718 pI830->LpRing->mem.Start) {
719 fprintf(stderr,
720 "I830SetRingRegs: Ring buffer start (%lx) violates its "
721 "mask (%x)\n", pI830->LpRing->mem.Start, I830_RING_START_MASK);
722 }
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);
726
727 if (((pI830->LpRing->mem.Size - 4096) & I830_RING_NR_PAGES) !=
728 pI830->LpRing->mem.Size - 4096) {
729 fprintf(stderr,
730 "I830SetRingRegs: Ring buffer size - 4096 (%lx) violates its "
731 "mask (%x)\n", pI830->LpRing->mem.Size - 4096,
732 I830_RING_NR_PAGES);
733 }
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);
738
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;
744
745 SetFenceRegs(ctx, pI830);
746
747 /* RESET THE DISPLAY PIPE TO POINT TO THE FRONTBUFFER - hacky
748 hacky hacky */
749 OUTREG(DSPABASE, pI830->FrontBuffer.Start + pI830->LinearAddr);
750
751 }
752
753 static Bool
754 I830SetParam(const DRIDriverContext *ctx, int param, int value)
755 {
756 drmI830SetParam sp;
757
758 memset(&sp, 0, sizeof(sp));
759 sp.param = param;
760 sp.value = value;
761
762 if (drmCommandWrite(ctx->drmFD, DRM_I830_SETPARAM, &sp, sizeof(sp))) {
763 fprintf(stderr, "I830 SetParam Failed\n");
764 return FALSE;
765 }
766
767 return TRUE;
768 }
769
770 static Bool
771 I830DRIMapScreenRegions(DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea)
772 {
773 fprintf(stderr,
774 "[drm] Mapping front buffer\n");
775
776 if (drmAddMap(ctx->drmFD,
777 (drm_handle_t)(sarea->front_offset + pI830->LinearAddr),
778 sarea->front_size,
779 DRM_FRAME_BUFFER, /*DRM_AGP,*/
780 0,
781 &sarea->front_handle) < 0) {
782 fprintf(stderr,
783 "[drm] drmAddMap(front_handle) failed. Disabling DRI\n");
784 return FALSE;
785 }
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);
790
791 if (drmAddMap(ctx->drmFD,
792 (drm_handle_t)(sarea->back_offset),
793 sarea->back_size, DRM_AGP, 0,
794 &sarea->back_handle) < 0) {
795 fprintf(stderr,
796 "[drm] drmAddMap(back_handle) failed. Disabling DRI\n");
797 return FALSE;
798 }
799 fprintf(stderr, "[drm] Back Buffer = 0x%08x\n",
800 sarea->back_handle);
801
802 if (drmAddMap(ctx->drmFD,
803 (drm_handle_t)sarea->depth_offset,
804 sarea->depth_size, DRM_AGP, 0,
805 &sarea->depth_handle) < 0) {
806 fprintf(stderr,
807 "[drm] drmAddMap(depth_handle) failed. Disabling DRI\n");
808 return FALSE;
809 }
810 fprintf(stderr, "[drm] Depth Buffer = 0x%08x\n",
811 sarea->depth_handle);
812
813 if (drmAddMap(ctx->drmFD,
814 (drm_handle_t)sarea->tex_offset,
815 sarea->tex_size, DRM_AGP, 0,
816 &sarea->tex_handle) < 0) {
817 fprintf(stderr,
818 "[drm] drmAddMap(tex_handle) failed. Disabling DRI\n");
819 return FALSE;
820 }
821 fprintf(stderr, "[drm] textures = 0x%08x\n",
822 sarea->tex_handle);
823
824 return TRUE;
825 }
826
827
828 static void
829 I830DRIUnmapScreenRegions(const DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea)
830 {
831 #if 1
832 if (sarea->front_handle) {
833 drmRmMap(ctx->drmFD, sarea->front_handle);
834 sarea->front_handle = 0;
835 }
836 #endif
837 if (sarea->back_handle) {
838 drmRmMap(ctx->drmFD, sarea->back_handle);
839 sarea->back_handle = 0;
840 }
841 if (sarea->depth_handle) {
842 drmRmMap(ctx->drmFD, sarea->depth_handle);
843 sarea->depth_handle = 0;
844 }
845 if (sarea->tex_handle) {
846 drmRmMap(ctx->drmFD, sarea->tex_handle);
847 sarea->tex_handle = 0;
848 }
849 }
850
851 static void
852 I830InitTextureHeap(const DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea)
853 {
854 /* Start up the simple memory manager for agp space */
855 drmI830MemInitHeap drmHeap;
856 drmHeap.region = I830_MEM_REGION_AGP;
857 drmHeap.start = 0;
858 drmHeap.size = sarea->tex_size;
859
860 if (drmCommandWrite(ctx->drmFD, DRM_I830_INIT_HEAP,
861 &drmHeap, sizeof(drmHeap))) {
862 fprintf(stderr,
863 "[drm] Failed to initialized agp heap manager\n");
864 } else {
865 fprintf(stderr,
866 "[drm] Initialized kernel agp heap manager, %d\n",
867 sarea->tex_size);
868
869 I830SetParam(ctx, I830_SETPARAM_TEX_LRU_LOG_GRANULARITY,
870 sarea->log_tex_granularity);
871 }
872 }
873
874 static Bool
875 I830DRIDoMappings(DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea)
876 {
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) {
881 fprintf(stderr,
882 "[drm] drmAddMap(ring_map) failed. Disabling DRI\n");
883 return FALSE;
884 }
885 fprintf(stderr, "[drm] ring buffer = 0x%08x\n",
886 pI830->ring_map);
887
888 if (I830InitDma(ctx, pI830) == FALSE) {
889 return FALSE;
890 }
891
892 /* init to zero to be safe */
893
894 I830DRIMapScreenRegions(ctx, pI830, sarea);
895 I830InitTextureHeap(ctx, pI830, sarea);
896
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 );
900 }
901
902 /* Okay now initialize the dma engine */
903 {
904 pI830->irq = drmGetInterruptFromBusID(ctx->drmFD,
905 ctx->pciBus,
906 ctx->pciDevice,
907 ctx->pciFunc);
908
909 if (drmCtlInstHandler(ctx->drmFD, pI830->irq)) {
910 fprintf(stderr,
911 "[drm] failure adding irq handler\n");
912 pI830->irq = 0;
913 return FALSE;
914 }
915 else
916 fprintf(stderr,
917 "[drm] dma control initialized, using IRQ %d\n",
918 pI830->irq);
919 }
920
921 fprintf(stderr, "[dri] visual configs initialized\n");
922
923 return TRUE;
924 }
925
926 static Bool
927 I830ClearScreen(DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea)
928 {
929 /* need to drmMap front and back buffers and zero them */
930 drmAddress map_addr;
931 int ret;
932
933 ret = drmMap(ctx->drmFD,
934 sarea->front_handle,
935 sarea->front_size,
936 &map_addr);
937
938 if (ret)
939 {
940 fprintf(stderr, "Unable to map front buffer\n");
941 return FALSE;
942 }
943
944 drimemsetio((char *)map_addr,
945 0,
946 sarea->front_size);
947 drmUnmap(map_addr, sarea->front_size);
948
949
950 ret = drmMap(ctx->drmFD,
951 sarea->back_handle,
952 sarea->back_size,
953 &map_addr);
954
955 if (ret)
956 {
957 fprintf(stderr, "Unable to map back buffer\n");
958 return FALSE;
959 }
960
961 drimemsetio((char *)map_addr,
962 0,
963 sarea->back_size);
964 drmUnmap(map_addr, sarea->back_size);
965
966 return TRUE;
967 }
968
969 static Bool
970 I830ScreenInit(DRIDriverContext *ctx, I830Rec *pI830)
971
972 {
973 I830DRIPtr pI830DRI;
974 drmI830Sarea *pSAREAPriv;
975 int err;
976
977 drm_page_size = getpagesize();
978
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.
984 */
985 ctx->shared.SAREASize = SAREA_MAX;
986
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");
991 return 0;
992 }
993
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));
997 return 0;
998 }
999
1000 if (drmAddMap( ctx->drmFD,
1001 0,
1002 ctx->shared.SAREASize,
1003 DRM_SHM,
1004 DRM_CONTAINS_LOCK,
1005 &ctx->shared.hSAREA) < 0)
1006 {
1007 fprintf(stderr, "[drm] drmAddMap failed\n");
1008 return 0;
1009 }
1010
1011 fprintf(stderr, "[drm] added %d byte SAREA at 0x%08x\n",
1012 ctx->shared.SAREASize, ctx->shared.hSAREA);
1013
1014 if (drmMap( ctx->drmFD,
1015 ctx->shared.hSAREA,
1016 ctx->shared.SAREASize,
1017 (drmAddressPtr)(&ctx->pSAREA)) < 0)
1018 {
1019 fprintf(stderr, "[drm] drmMap failed\n");
1020 return 0;
1021
1022 }
1023
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);
1027
1028
1029 if (drmAddMap(ctx->drmFD,
1030 ctx->MMIOStart,
1031 ctx->MMIOSize,
1032 DRM_REGISTERS,
1033 DRM_READ_ONLY,
1034 &pI830->registerHandle) < 0) {
1035 fprintf(stderr, "[drm] drmAddMap mmio failed\n");
1036 return 0;
1037 }
1038 fprintf(stderr,
1039 "[drm] register handle = 0x%08x\n", pI830->registerHandle);
1040
1041
1042 if (!I830CheckDRMVersion(ctx, pI830)) {
1043 return FALSE;
1044 }
1045
1046 /* Create a 'server' context so we can grab the lock for
1047 * initialization ioctls.
1048 */
1049 if ((err = drmCreateContext(ctx->drmFD, &ctx->serverContext)) != 0) {
1050 fprintf(stderr, "%s: drmCreateContext failed %d\n", __FUNCTION__, err);
1051 return 0;
1052 }
1053
1054 DRM_LOCK(ctx->drmFD, ctx->pSAREA, ctx->serverContext, 0);
1055
1056 /* Initialize the SAREA private data structure */
1057 pSAREAPriv = (drmI830Sarea *)(((char*)ctx->pSAREA) +
1058 sizeof(drm_sarea_t));
1059 memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
1060
1061 pI830->StolenMemory.Size = I830DetectMemory(ctx, pI830);
1062 pI830->StolenMemory.Start = 0;
1063 pI830->StolenMemory.End = pI830->StolenMemory.Size;
1064
1065 pI830->MemoryAperture.Start = pI830->StolenMemory.End;
1066 pI830->MemoryAperture.End = KB(40000);
1067 pI830->MemoryAperture.Size = pI830->MemoryAperture.End - pI830->MemoryAperture.Start;
1068
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;
1073
1074 if (!AgpInit(ctx, pI830))
1075 return FALSE;
1076
1077 if (I830AllocateMemory(ctx, pI830) == FALSE)
1078 {
1079 return FALSE;
1080 }
1081
1082 if (I830BindMemory(ctx, pI830) == FALSE)
1083 {
1084 return FALSE;
1085 }
1086
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;
1101
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;
1113
1114 pI830DRI->depthOffset = pI830->DepthBuffer.Start;
1115 pI830DRI->depthPitch = pI830->DepthBuffer.Pitch;
1116
1117 pI830DRI->fbOffset = pI830->FrontBuffer.Start;
1118 pI830DRI->fbStride = pI830->FrontBuffer.Pitch;
1119
1120 pI830DRI->bitsPerPixel = ctx->bpp;
1121 pI830DRI->sarea_priv_offset = sizeof(drm_sarea_t);
1122
1123 err = I830DRIDoMappings(ctx, pI830, pSAREAPriv);
1124 if (err == FALSE)
1125 return FALSE;
1126
1127 I830SetupMemoryTiling(ctx, pI830);
1128
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
1131 * first.
1132 */
1133 I830ClearScreen(ctx, pI830, pSAREAPriv);
1134
1135 I830SetRingRegs(ctx, pI830);
1136
1137 return TRUE;
1138 }
1139
1140
1141 /**
1142 * \brief Validate the fbdev mode.
1143 *
1144 * \param ctx display handle.
1145 *
1146 * \return one on success, or zero on failure.
1147 *
1148 * Saves some registers and returns 1.
1149 *
1150 * \sa radeonValidateMode().
1151 */
1152 static int i830ValidateMode( const DRIDriverContext *ctx )
1153 {
1154 return 1;
1155 }
1156
1157 /**
1158 * \brief Examine mode returned by fbdev.
1159 *
1160 * \param ctx display handle.
1161 *
1162 * \return one on success, or zero on failure.
1163 *
1164 * Restores registers that fbdev has clobbered and returns 1.
1165 *
1166 * \sa i810ValidateMode().
1167 */
1168 static int i830PostValidateMode( const DRIDriverContext *ctx )
1169 {
1170 I830Rec *pI830 = ctx->driverPrivate;
1171
1172 I830SetRingRegs(ctx, pI830);
1173 return 1;
1174 }
1175
1176
1177 /**
1178 * \brief Initialize the framebuffer device mode
1179 *
1180 * \param ctx display handle.
1181 *
1182 * \return one on success, or zero on failure.
1183 *
1184 * Fills in \p info with some default values and some information from \p ctx
1185 * and then calls I810ScreenInit() for the screen initialization.
1186 *
1187 * Before exiting clears the framebuffer memory accessing it directly.
1188 */
1189 static int i830InitFBDev( DRIDriverContext *ctx )
1190 {
1191 I830Rec *pI830 = calloc(1, sizeof(I830Rec));
1192 int i;
1193
1194 {
1195 int dummy = ctx->shared.virtualWidth;
1196
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;
1200 case 3:
1201 case 4: dummy = (ctx->shared.virtualWidth + 15) & ~15; break;
1202 }
1203
1204 ctx->shared.virtualWidth = dummy;
1205 ctx->shared.Width = ctx->shared.virtualWidth;
1206 }
1207
1208
1209 for (i = 0; pitches[i] != 0; i++) {
1210 if (pitches[i] >= ctx->shared.virtualWidth) {
1211 ctx->shared.virtualWidth = pitches[i];
1212 break;
1213 }
1214 }
1215
1216 ctx->driverPrivate = (void *)pI830;
1217
1218 pI830->LpRing = calloc(1, sizeof(I830RingBuffer));
1219 pI830->Chipset = ctx->chipset;
1220 pI830->LinearAddr = ctx->FBStart;
1221
1222 if (!I830ScreenInit( ctx, pI830 ))
1223 return 0;
1224
1225
1226 return 1;
1227 }
1228
1229
1230 /**
1231 * \brief The screen is being closed, so clean up any state and free any
1232 * resources used by the DRI.
1233 *
1234 * \param ctx display handle.
1235 *
1236 * Unmaps the SAREA, closes the DRM device file descriptor and frees the driver
1237 * private data.
1238 */
1239 static void i830HaltFBDev( DRIDriverContext *ctx )
1240 {
1241 drmI830Sarea *pSAREAPriv;
1242 I830Rec *pI830 = ctx->driverPrivate;
1243
1244 if (pI830->irq) {
1245 drmCtlUninstHandler(ctx->drmFD);
1246 pI830->irq = 0; }
1247
1248 I830CleanupDma(ctx);
1249
1250 pSAREAPriv = (drmI830Sarea *)(((char*)ctx->pSAREA) +
1251 sizeof(drm_sarea_t));
1252
1253 I830DRIUnmapScreenRegions(ctx, pI830, pSAREAPriv);
1254 drmUnmap( ctx->pSAREA, ctx->shared.SAREASize );
1255 drmClose(ctx->drmFD);
1256
1257 if (ctx->driverPrivate) {
1258 free(ctx->driverPrivate);
1259 ctx->driverPrivate = 0;
1260 }
1261 }
1262
1263
1264 extern void i810NotifyFocus( int );
1265
1266 /**
1267 * \brief Exported driver interface for Mini GLX.
1268 *
1269 * \sa DRIDriverRec.
1270 */
1271 const struct DRIDriverRec __driDriver = {
1272 i830ValidateMode,
1273 i830PostValidateMode,
1274 i830InitFBDev,
1275 i830HaltFBDev,
1276 NULL,//I830EngineShutdown,
1277 NULL, //I830EngineRestore,
1278 #ifndef _EMBEDDED
1279 0,
1280 #else
1281 i810NotifyFocus,
1282 #endif
1283 };