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