i810_driver.c revision 03b705cf
1
2/**************************************************************************
3
4Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
5All Rights Reserved.
6
7Permission is hereby granted, free of charge, to any person obtaining a
8copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sub license, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice (including the
16next paragraph) shall be included in all copies or substantial portions
17of the Software.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
23ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
27**************************************************************************/
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33/*
34 * Authors:
35 *   Keith Whitwell <keith@tungstengraphics.com>
36 *
37 * Add ARGB HW cursor support:
38 *   Alan Hourihane <alanh@tungstengraphics.com>
39 *
40 */
41
42/*
43 * This server does not support these XFree86 4.0 features yet
44 * shadowFb (if requested or acceleration is off)
45 * Overlay planes
46 * DGA
47 */
48
49#include <math.h>
50#include <string.h>
51#include <unistd.h>
52
53/*
54 * These are X and server generic header files.
55 */
56#include "xf86.h"
57#include "xf86_OSproc.h"
58#include "xf86cmap.h"
59
60#include "compiler.h"
61#include "vgaHW.h"
62#include "mipointer.h"
63#include "micmap.h"
64
65#include "fb.h"
66#include "miscstruct.h"
67#include "xf86xv.h"
68#include <X11/extensions/Xv.h>
69#include "vbe.h"
70#include "xf86fbman.h"
71
72#include "i810.h"
73
74#ifdef HAVE_DRI1
75#include "dri.h"
76#endif
77
78#include "../legacy.h"
79
80static Bool I810PreInit(ScrnInfoPtr pScrn, int flags);
81static Bool I810ScreenInit(SCREEN_INIT_ARGS_DECL);
82static Bool I810EnterVT(VT_FUNC_ARGS_DECL);
83static void I810LeaveVT(VT_FUNC_ARGS_DECL);
84static Bool I810CloseScreen(CLOSE_SCREEN_ARGS_DECL);
85static Bool I810SaveScreen(ScreenPtr pScreen, Bool unblank);
86static void I810FreeScreen(FREE_SCREEN_ARGS_DECL);
87static void I810DisplayPowerManagementSet(ScrnInfoPtr pScrn,
88					  int PowerManagermentMode,
89					  int flags);
90static ModeStatus I810ValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode,
91				Bool verbose, int flags);
92
93typedef enum {
94   OPTION_NOACCEL,
95   OPTION_SW_CURSOR,
96   OPTION_COLOR_KEY,
97   OPTION_CACHE_LINES,
98   OPTION_DAC_6BIT,
99   OPTION_DRI,
100   OPTION_NO_DDC,
101   OPTION_SHOW_CACHE,
102   OPTION_XVMC_SURFACES,
103   OPTION_PAGEFLIP
104} I810Opts;
105
106static const OptionInfoRec I810Options[] = {
107   {OPTION_NOACCEL,		"NoAccel",	OPTV_BOOLEAN,	{0}, FALSE},
108   {OPTION_SW_CURSOR,		"SWcursor",	OPTV_BOOLEAN,	{0}, FALSE},
109   {OPTION_COLOR_KEY,		"ColorKey",	OPTV_INTEGER,	{0}, FALSE},
110   {OPTION_CACHE_LINES,		"CacheLines",	OPTV_INTEGER,	{0}, FALSE},
111   {OPTION_DAC_6BIT,		"Dac6Bit",	OPTV_BOOLEAN,	{0}, FALSE},
112   {OPTION_DRI,			"DRI",		OPTV_BOOLEAN,	{0}, FALSE},
113   {OPTION_NO_DDC,		"NoDDC",	OPTV_BOOLEAN,	{0}, FALSE},
114   {OPTION_SHOW_CACHE,		"ShowCache",	OPTV_BOOLEAN,	{0}, FALSE},
115   {OPTION_XVMC_SURFACES,	"XvMCSurfaces",	OPTV_INTEGER,	{0}, FALSE},
116   {OPTION_PAGEFLIP,            "PageFlip",     OPTV_BOOLEAN, {0},   FALSE},
117   {-1,				NULL,		OPTV_NONE,	{0}, FALSE}
118};
119/* *INDENT-ON* */
120
121#ifndef I810_DEBUG
122int I810_DEBUG = (0
123/*     		  | DEBUG_ALWAYS_SYNC  */
124/*    		  | DEBUG_VERBOSE_ACCEL */
125/*  		  | DEBUG_VERBOSE_SYNC */
126/*  		  | DEBUG_VERBOSE_VGA */
127/*  		  | DEBUG_VERBOSE_RING */
128/*  		  | DEBUG_VERBOSE_OUTREG */
129/*  		  | DEBUG_VERBOSE_MEMORY */
130/*  		  | DEBUG_VERBOSE_CURSOR */
131      );
132#endif
133
134#ifdef HAVE_DRI1
135static int i810_pitches[] = {
136   512,
137   1024,
138   2048,
139   4096,
140   0
141};
142#endif
143
144/*
145 * I810GetRec and I810FreeRec --
146 *
147 * Private data for the driver is stored in the screen structure.
148 * These two functions create and destroy that private data.
149 *
150 */
151static Bool
152I810GetRec(ScrnInfoPtr scrn)
153{
154   if (((uintptr_t)scrn->driverPrivate & 1) == 0)
155      return TRUE;
156
157   scrn->driverPrivate = xnfcalloc(sizeof(I810Rec), 1);
158   return TRUE;
159}
160
161static void
162I810FreeRec(ScrnInfoPtr scrn)
163{
164   if (!scrn)
165      return;
166   if (!scrn->driverPrivate)
167      return;
168   free(scrn->driverPrivate);
169   scrn->driverPrivate = NULL;
170}
171
172struct pci_device *
173intel_host_bridge (void)
174{
175    static const struct pci_slot_match bridge_match = {
176	0, 0, 0, PCI_MATCH_ANY, 0
177    };
178    struct pci_device_iterator	*slot_iterator;
179    struct pci_device		*bridge;
180
181    slot_iterator = pci_slot_match_iterator_create (&bridge_match);
182    bridge = pci_device_next (slot_iterator);
183    pci_iterator_destroy (slot_iterator);
184    return bridge;
185}
186
187static void
188I810ProbeDDC(ScrnInfoPtr scrn, int index)
189{
190   vbeInfoPtr pVbe;
191
192   if (xf86LoadSubModule(scrn, "vbe")) {
193      pVbe = VBEInit(NULL, index);
194      ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
195      vbeFree(pVbe);
196   }
197}
198
199static xf86MonPtr
200I810DoDDC(ScrnInfoPtr scrn, int index)
201{
202   vbeInfoPtr pVbe;
203   xf86MonPtr MonInfo = NULL;
204   I810Ptr pI810 = I810PTR(scrn);
205
206   /* Honour Option "noDDC" */
207   if (xf86ReturnOptValBool(pI810->Options, OPTION_NO_DDC, FALSE)) {
208      return MonInfo;
209   }
210
211   if (xf86LoadSubModule(scrn, "vbe") && (pVbe = VBEInit(NULL, index))) {
212      MonInfo = vbeDoEDID(pVbe, NULL);
213      xf86PrintEDID(MonInfo);
214      xf86SetDDCproperties(scrn, MonInfo);
215      vbeFree(pVbe);
216   } else {
217      xf86DrvMsg(scrn->scrnIndex, X_INFO,
218		 "this driver cannot do DDC without VBE\n");
219   }
220
221   return MonInfo;
222}
223
224/*
225 * I810PreInit --
226 *
227 * Do initial setup of the board before we know what resolution we will
228 * be running at.
229 *
230 */
231static Bool
232I810PreInit(ScrnInfoPtr scrn, int flags)
233{
234   I810Ptr pI810;
235   ClockRangePtr clockRanges;
236   int i;
237   MessageType from;
238   int flags24;
239   rgb defaultWeight = { 0, 0, 0 };
240   int mem;
241   Bool enable;
242
243   if (scrn->numEntities != 1)
244      return FALSE;
245
246   /* Allocate driverPrivate */
247   if (!I810GetRec(scrn))
248      return FALSE;
249
250   pI810 = I810PTR(scrn);
251
252   pI810->pEnt = xf86GetEntityInfo(scrn->entityList[0]);
253   if (pI810->pEnt == NULL || pI810->pEnt->location.type != BUS_PCI)
254      return FALSE;
255
256   if (flags & PROBE_DETECT) {
257      I810ProbeDDC(scrn, pI810->pEnt->index);
258      return TRUE;
259   }
260
261   /* The vgahw module should be loaded here when needed */
262   if (!xf86LoadSubModule(scrn, "vgahw"))
263      return FALSE;
264
265   /* Allocate a vgaHWRec */
266   if (!vgaHWGetHWRec(scrn))
267      return FALSE;
268
269   pI810->PciInfo = xf86GetPciInfoForEntity(pI810->pEnt->index);
270
271   /* Set scrn->monitor */
272   scrn->monitor = scrn->confScreen->monitor;
273
274   flags24 = Support24bppFb | PreferConvert32to24 | SupportConvert32to24;
275   if (!xf86SetDepthBpp(scrn, 16, 0, 16, flags24)) {
276      return FALSE;
277   } else {
278      switch (scrn->depth) {
279      case 8:
280      case 15:
281      case 16:
282      case 24:
283	 break;
284      default:
285	 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
286		    "Given depth (%d) is not supported by i810 driver\n",
287		    scrn->depth);
288	 return FALSE;
289      }
290   }
291   xf86PrintDepthBpp(scrn);
292
293   switch (scrn->bitsPerPixel) {
294   case 8:
295   case 16:
296   case 24:
297      break;
298   default:
299      xf86DrvMsg(scrn->scrnIndex, X_ERROR,
300		 "Given bpp (%d) is not supported by i810 driver\n",
301		 scrn->bitsPerPixel);
302      return FALSE;
303   }
304
305   if (!xf86SetWeight(scrn, defaultWeight, defaultWeight))
306      return FALSE;
307
308   if (!xf86SetDefaultVisual(scrn, -1))
309      return FALSE;
310
311   /* We use a programmable clock */
312   scrn->progClock = TRUE;
313
314   pI810->cpp = scrn->bitsPerPixel / 8;
315
316   /* Process the options */
317   xf86CollectOptions(scrn, NULL);
318   if (!(pI810->Options = malloc(sizeof(I810Options))))
319      return FALSE;
320   memcpy(pI810->Options, I810Options, sizeof(I810Options));
321   xf86ProcessOptions(scrn->scrnIndex, scrn->options, pI810->Options);
322
323   scrn->rgbBits = 8;
324   if (xf86ReturnOptValBool(pI810->Options, OPTION_DAC_6BIT, FALSE))
325      scrn->rgbBits = 6;
326
327   if (xf86ReturnOptValBool(pI810->Options, OPTION_SHOW_CACHE, FALSE))
328     pI810->showCache = TRUE;
329   else
330     pI810->showCache = FALSE;
331
332   /* 6-BIT dac isn't reasonable for modes with > 8bpp */
333   if (xf86ReturnOptValBool(pI810->Options, OPTION_DAC_6BIT, FALSE) &&
334       scrn->bitsPerPixel > 8) {
335      OptionInfoPtr ptr;
336
337      ptr = xf86TokenToOptinfo(pI810->Options, OPTION_DAC_6BIT);
338      ptr->found = FALSE;
339   }
340
341   if (xf86ReturnOptValBool(pI810->Options, OPTION_NOACCEL, FALSE))
342      pI810->noAccel = TRUE;
343
344   if (!pI810->noAccel && !xf86LoadSubModule(scrn, "xaa"))
345      pI810->noAccel = TRUE;
346
347#ifdef HAVE_DRI1
348   pI810->directRenderingDisabled =
349     !xf86ReturnOptValBool(pI810->Options, OPTION_DRI, TRUE);
350
351   if (!pI810->directRenderingDisabled) {
352     if (scrn->depth!=16) {
353       xf86DrvMsg(scrn->scrnIndex, X_WARNING, "DRI is disabled because it "
354		  "runs only at 16-bit depth.\n");
355       pI810->directRenderingDisabled=TRUE;
356     }
357   }
358#endif
359
360   /* Get DDC info from monitor */
361   /* after xf86ProcessOptions,
362    * because it is controlled by options [no]vbe and [no]ddc
363    */
364   I810DoDDC(scrn, pI810->pEnt->index);
365
366   intel_detect_chipset(scrn, pI810->pEnt, pI810->PciInfo);
367
368   pI810->LinearAddr = pI810->PciInfo->regions[0].base_addr;
369   xf86DrvMsg(scrn->scrnIndex, X_PROBED, "Linear framebuffer at 0x%lX\n",
370	      (unsigned long)pI810->LinearAddr);
371
372   pI810->MMIOAddr = pI810->PciInfo->regions[1].base_addr;
373   xf86DrvMsg(scrn->scrnIndex, X_PROBED, "IO registers at addr 0x%lX\n",
374	      (unsigned long)pI810->MMIOAddr);
375
376   /* AGP GART support is required.  Don't proceed any further if it isn't
377    * present.
378    */
379   if (!xf86AgpGARTSupported()) {
380      xf86DrvMsg(scrn->scrnIndex, X_ERROR,
381		 "AGP GART support is not available.  Make sure your kernel has\n"
382		 "\tagpgart support or that the agpgart kernel module is loaded.\n");
383      return FALSE;
384   }
385
386   /* Find out memory bus frequency.
387    */
388   {
389      uint32_t whtcfg_pamr_drp;
390
391      pci_device_cfg_read_u32(pI810->PciInfo, & whtcfg_pamr_drp, WHTCFG_PAMR_DRP);
392
393      /* Need this for choosing watermarks.
394       */
395      if ((whtcfg_pamr_drp & LM_FREQ_MASK) == LM_FREQ_133)
396	 pI810->LmFreqSel = 133;
397      else
398	 pI810->LmFreqSel = 100;
399   }
400
401   /* Default to 4MB framebuffer, which is sufficient for all
402    * supported 2d resolutions.  If the user has specified a different
403    * size in the XF86Config, use that amount instead.
404    *
405    *  Changed to 8 Meg so we can have acceleration by default (Mark).
406    */
407   mem = I810CheckAvailableMemory(scrn);
408   if (pI810->directRenderingDisabled || mem < 131072)  /* < 128 MB */
409       scrn->videoRam = 8192;
410   else if (mem < 196608)
411       scrn->videoRam = 16384;  /* < 192 MB */
412   else
413       scrn->videoRam = 24576;
414
415   from = X_DEFAULT;
416
417   if (pI810->pEnt->device->videoRam) {
418      scrn->videoRam = pI810->pEnt->device->videoRam;
419      from = X_CONFIG;
420   }
421
422   if (mem > 0 && mem < scrn->videoRam) {
423      xf86DrvMsg(scrn->scrnIndex, X_WARNING, "%dk of memory was requested,"
424		 " but the\n\t maximum AGP memory available is %dk.\n",
425		 scrn->videoRam, mem);
426      from = X_PROBED;
427      if (mem > (6 * 1024)) {
428	 xf86DrvMsg(scrn->scrnIndex, X_INFO,
429		    "Reducing video memory to 4MB\n");
430	 scrn->videoRam = 4096;
431      } else {
432	 xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Less than 6MB of AGP memory"
433		    " is available. Cannot proceed.\n");
434	 I810FreeRec(scrn);
435	 return FALSE;
436      }
437   }
438
439   xf86DrvMsg(scrn->scrnIndex, from,
440	      "Will alloc AGP framebuffer: %d kByte\n", scrn->videoRam);
441
442   /* Calculate Fixed Offsets depending on graphics aperture size */
443   {
444      struct pci_device *bridge = intel_host_bridge ();
445      uint32_t   smram_miscc;
446
447      pci_device_cfg_read_u32 (bridge, & smram_miscc, SMRAM_MISCC);
448
449      if ((smram_miscc & GFX_MEM_WIN_SIZE) == GFX_MEM_WIN_32M) {
450	 pI810->FbMapSize = 0x1000000;
451	 pI810->DepthOffset = 0x1000000;
452	 pI810->BackOffset = 0x1800000;
453      } else {
454	 pI810->FbMapSize = 0x3000000;
455	 pI810->DepthOffset = 0x3000000;
456	 pI810->BackOffset = 0x3800000;
457      }
458   }
459
460   /*
461    * If the driver can do gamma correction, it should call xf86SetGamma()
462    * here.
463    */
464   {
465      Gamma zeros = { 0.0, 0.0, 0.0 };
466
467      if (!xf86SetGamma(scrn, zeros)) {
468	 return FALSE;
469      }
470   }
471
472   pI810->MaxClock = 0;
473   if (pI810->pEnt->device->dacSpeeds[0]) {
474      switch (scrn->bitsPerPixel) {
475      case 8:
476	 pI810->MaxClock = pI810->pEnt->device->dacSpeeds[DAC_BPP8];
477	 break;
478      case 16:
479	 pI810->MaxClock = pI810->pEnt->device->dacSpeeds[DAC_BPP16];
480	 break;
481      case 24:
482	 pI810->MaxClock = pI810->pEnt->device->dacSpeeds[DAC_BPP24];
483	 break;
484      case 32:				/* not supported */
485	 pI810->MaxClock = pI810->pEnt->device->dacSpeeds[DAC_BPP32];
486	 break;
487      }
488      if (!pI810->MaxClock)
489	 pI810->MaxClock = pI810->pEnt->device->dacSpeeds[0];
490   } else {
491      switch (scrn->bitsPerPixel) {
492      case 8:
493	 pI810->MaxClock = 203000;
494	 break;
495      case 16:
496	 pI810->MaxClock = 163000;
497	 break;
498      case 24:
499	 pI810->MaxClock = 136000;
500	 break;
501      case 32:				/* not supported */
502	 pI810->MaxClock = 86000;
503      }
504   }
505   clockRanges = xnfcalloc(sizeof(ClockRange), 1);
506   clockRanges->next = NULL;
507   /* 9.4MHz appears to be the smallest that works. */
508   clockRanges->minClock = 9500;
509   clockRanges->maxClock = pI810->MaxClock;
510   clockRanges->clockIndex = -1;
511   clockRanges->interlaceAllowed = TRUE;
512   clockRanges->doubleScanAllowed = FALSE;
513
514   i = xf86ValidateModes(scrn, scrn->monitor->Modes,
515			 scrn->display->modes, clockRanges,
516#ifndef HAVE_DRI1
517			 0, 320, 1600, 64 * scrn->bitsPerPixel,
518#else
519			 i810_pitches, 0, 0, 64 * scrn->bitsPerPixel,
520#endif
521			 200, 1200,
522			 scrn->display->virtualX, scrn->display->virtualY,
523			 scrn->videoRam * 1024, LOOKUP_BEST_REFRESH);
524
525   if (i == -1) {
526      I810FreeRec(scrn);
527      return FALSE;
528   }
529
530   xf86PruneDriverModes(scrn);
531
532   if (!i || !scrn->modes) {
533      xf86DrvMsg(scrn->scrnIndex, X_ERROR, "No valid modes found\n");
534      I810FreeRec(scrn);
535      return FALSE;
536   }
537
538   xf86SetCrtcForModes(scrn, INTERLACE_HALVE_V);
539
540   scrn->currentMode = scrn->modes;
541
542   xf86PrintModes(scrn);
543
544   xf86SetDpi(scrn, 0, 0);
545
546   if (!xf86LoadSubModule(scrn, "fb")) {
547      I810FreeRec(scrn);
548      return FALSE;
549   }
550
551   if (!xf86ReturnOptValBool(pI810->Options, OPTION_SW_CURSOR, FALSE)) {
552      if (!xf86LoadSubModule(scrn, "ramdac")) {
553	 I810FreeRec(scrn);
554	 return FALSE;
555      }
556   }
557
558   if (xf86GetOptValInteger
559       (pI810->Options, OPTION_COLOR_KEY, &(pI810->colorKey))) {
560      xf86DrvMsg(scrn->scrnIndex, X_CONFIG,
561		 "video overlay key set to 0x%x\n", pI810->colorKey);
562   } else {
563      pI810->colorKey = (1 << scrn->offset.red) |
564	    (1 << scrn->offset.green) |
565	    (((scrn->mask.blue >> scrn->offset.blue) -
566	      1) << scrn->offset.blue);
567   }
568
569   pI810->allowPageFlip=FALSE;
570   enable = xf86ReturnOptValBool(pI810->Options, OPTION_PAGEFLIP, FALSE);
571
572#ifdef HAVE_DRI1
573   if (!pI810->directRenderingDisabled) {
574     pI810->allowPageFlip = enable;
575     if (pI810->allowPageFlip == TRUE)
576     {
577       if (!xf86LoadSubModule(scrn, "shadowfb")) {
578	 pI810->allowPageFlip = 0;
579	 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
580		    "Couldn't load shadowfb module:\n");
581       }
582     }
583
584     xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "page flipping %s\n",
585		enable ? "enabled" : "disabled");
586
587   }
588#endif
589
590   if (xf86GetOptValInteger(pI810->Options, OPTION_XVMC_SURFACES,
591			    &(pI810->numSurfaces))) {
592      xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "%d XvMC Surfaces Requested.\n",
593		 pI810->numSurfaces);
594      if (pI810->numSurfaces > 7) {
595	 xf86DrvMsg(scrn->scrnIndex, X_PROBED,
596		    "Using 7 XvMC Surfaces (Maximum Allowed).\n");
597	 pI810->numSurfaces = 7;
598      }
599      if (pI810->numSurfaces < 6) {
600	 xf86DrvMsg(scrn->scrnIndex, X_PROBED,
601		    "Using 6 XvMC Surfaces (Minimum Allowed).\n");
602	 pI810->numSurfaces = 6;
603      }
604   } else {
605      xf86DrvMsg(scrn->scrnIndex, X_INFO,
606		 "XvMC is Disabled: use XvMCSurfaces config option to enable.\n");
607      pI810->numSurfaces = 0;
608   }
609
610#ifdef HAVE_DRI1
611   /* Load the dri module if requested. */
612   if (xf86ReturnOptValBool(pI810->Options, OPTION_DRI, FALSE)) {
613      xf86LoadSubModule(scrn, "dri");
614   }
615#endif
616
617   return TRUE;
618}
619
620static Bool
621I810MapMMIO(ScrnInfoPtr scrn)
622{
623   I810Ptr pI810 = I810PTR(scrn);
624   struct pci_device *const device = pI810->PciInfo;
625   int err;
626
627   err = pci_device_map_range (device,
628			       pI810->MMIOAddr,
629			       I810_REG_SIZE,
630			       PCI_DEV_MAP_FLAG_WRITABLE,
631			       (void **) &pI810->MMIOBase);
632   if (err)
633   {
634      xf86DrvMsg (scrn->scrnIndex, X_ERROR,
635		  "Unable to map mmio BAR. %s (%d)\n",
636		  strerror (err), err);
637      return FALSE;
638   }
639   return TRUE;
640}
641
642static Bool
643I810MapMem(ScrnInfoPtr scrn)
644{
645   I810Ptr pI810 = I810PTR(scrn);
646   struct pci_device *const device = pI810->PciInfo;
647   int err;
648
649   if (!I810MapMMIO(scrn))
650      return FALSE;
651
652   err = pci_device_map_range (device,
653			       pI810->LinearAddr,
654			       pI810->FbMapSize,
655			       PCI_DEV_MAP_FLAG_WRITABLE | PCI_DEV_MAP_FLAG_WRITE_COMBINE,
656			       (void **) &pI810->FbBase);
657   if (err)
658   {
659      xf86DrvMsg (scrn->scrnIndex, X_ERROR,
660		  "Unable to map frame buffer BAR. %s (%d)\n",
661		  strerror (err), err);
662      return FALSE;
663   }
664
665   pI810->LpRing->virtual_start = pI810->FbBase + pI810->LpRing->mem.Start;
666
667   return TRUE;
668}
669
670static void
671I810UnmapMMIO(ScrnInfoPtr scrn)
672{
673   I810Ptr pI810 = I810PTR(scrn);
674
675   pci_device_unmap_range (pI810->PciInfo, pI810->MMIOBase, I810_REG_SIZE);
676   pI810->MMIOBase = NULL;
677}
678
679static Bool
680I810UnmapMem(ScrnInfoPtr scrn)
681{
682   I810Ptr pI810 = I810PTR(scrn);
683
684   pci_device_unmap_range (pI810->PciInfo, pI810->FbBase, pI810->FbMapSize);
685   pI810->FbBase = NULL;
686   I810UnmapMMIO(scrn);
687   return TRUE;
688}
689
690/* Famous last words
691 */
692void
693I810PrintErrorState(ScrnInfoPtr scrn)
694{
695   I810Ptr pI810 = I810PTR(scrn);
696
697   ErrorF("pgetbl_ctl: 0x%lx pgetbl_err: 0x%lx\n",
698	  (unsigned long) INREG(PGETBL_CTL), (unsigned long) INREG(PGE_ERR));
699
700   ErrorF("ipeir: %lx iphdr: %lx\n", (unsigned long) INREG(IPEIR),
701	  (unsigned long) INREG(IPEHR));
702
703   ErrorF("LP ring tail: %lx head: %lx len: %lx start %lx\n",
704	  (unsigned long) INREG(LP_RING + RING_TAIL),
705	  (unsigned long) INREG(LP_RING + RING_HEAD) & HEAD_ADDR,
706	  (unsigned long) INREG(LP_RING + RING_LEN),
707	  (unsigned long) INREG(LP_RING + RING_START));
708
709   ErrorF("eir: %x esr: %x emr: %x\n",
710	  INREG16(EIR), INREG16(ESR), INREG16(EMR));
711
712   ErrorF("instdone: %x instpm: %x\n", INREG16(INST_DONE), INREG8(INST_PM));
713
714   ErrorF("memmode: %lx instps: %lx\n", (unsigned long) INREG(MEMMODE),
715	  (unsigned long) INREG(INST_PS));
716
717   ErrorF("hwstam: %x ier: %x imr: %x iir: %x\n",
718	  INREG16(HWSTAM), INREG16(IER), INREG16(IMR), INREG16(IIR));
719}
720
721/*
722 * I810Save --
723 *
724 * This function saves the video state.  It reads all of the SVGA registers
725 * into the vgaI810Rec data structure.  There is in general no need to
726 * mask out bits here - just read the registers.
727 */
728static void
729DoSave(ScrnInfoPtr scrn, vgaRegPtr vgaReg, I810RegPtr i810Reg,
730       Bool saveFonts)
731{
732   I810Ptr pI810;
733   vgaHWPtr hwp;
734   int i;
735
736   pI810 = I810PTR(scrn);
737   hwp = VGAHWPTR(scrn);
738
739   /*
740    * This function will handle creating the data structure and filling
741    * in the generic VGA portion.
742    */
743   if (saveFonts)
744      vgaHWSave(scrn, vgaReg, VGA_SR_MODE | VGA_SR_FONTS | VGA_SR_CMAP);
745   else
746      vgaHWSave(scrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP);
747
748   /*
749    * The port I/O code necessary to read in the extended registers
750    * into the fields of the vgaI810Rec structure goes here.
751    */
752   i810Reg->IOControl = hwp->readCrtc(hwp, IO_CTNL);
753   i810Reg->AddressMapping = hwp->readGr(hwp, ADDRESS_MAPPING);
754   i810Reg->BitBLTControl = INREG8(BITBLT_CNTL);
755   i810Reg->VideoClk2_M = INREG16(VCLK2_VCO_M);
756   i810Reg->VideoClk2_N = INREG16(VCLK2_VCO_N);
757   i810Reg->VideoClk2_DivisorSel = INREG8(VCLK2_VCO_DIV_SEL);
758
759   i810Reg->ExtVertTotal = hwp->readCrtc(hwp, EXT_VERT_TOTAL);
760   i810Reg->ExtVertDispEnd = hwp->readCrtc(hwp, EXT_VERT_DISPLAY);
761   i810Reg->ExtVertSyncStart = hwp->readCrtc(hwp, EXT_VERT_SYNC_START);
762   i810Reg->ExtVertBlankStart = hwp->readCrtc(hwp, EXT_VERT_BLANK_START);
763   i810Reg->ExtHorizTotal = hwp->readCrtc(hwp, EXT_HORIZ_TOTAL);
764   i810Reg->ExtHorizBlank = hwp->readCrtc(hwp, EXT_HORIZ_BLANK);
765   i810Reg->ExtOffset = hwp->readCrtc(hwp, EXT_OFFSET);
766   i810Reg->InterlaceControl = hwp->readCrtc(hwp, INTERLACE_CNTL);
767
768   i810Reg->PixelPipeCfg0 = INREG8(PIXPIPE_CONFIG_0);
769   i810Reg->PixelPipeCfg1 = INREG8(PIXPIPE_CONFIG_1);
770   i810Reg->PixelPipeCfg2 = INREG8(PIXPIPE_CONFIG_2);
771   i810Reg->DisplayControl = INREG8(DISPLAY_CNTL);
772   i810Reg->LMI_FIFO_Watermark = INREG(FWATER_BLC);
773
774   for (i = 0; i < 8; i++)
775      i810Reg->Fence[i] = INREG(FENCE + i * 4);
776
777   i810Reg->LprbTail = INREG(LP_RING + RING_TAIL);
778   i810Reg->LprbHead = INREG(LP_RING + RING_HEAD);
779   i810Reg->LprbStart = INREG(LP_RING + RING_START);
780   i810Reg->LprbLen = INREG(LP_RING + RING_LEN);
781
782   if ((i810Reg->LprbTail & TAIL_ADDR) != (i810Reg->LprbHead & HEAD_ADDR) &&
783       i810Reg->LprbLen & RING_VALID) {
784      I810PrintErrorState(scrn);
785      FatalError("Active ring not flushed\n");
786   }
787}
788
789static void
790I810Save(ScrnInfoPtr scrn)
791{
792   vgaHWPtr hwp;
793   I810Ptr pI810;
794   uint32_t temp;
795
796   hwp = VGAHWPTR(scrn);
797   pI810 = I810PTR(scrn);
798   DoSave(scrn, &hwp->SavedReg, &pI810->SavedReg, TRUE);
799
800   temp = INREG(MEMMODE);
801   temp |= 4;
802   OUTREG(MEMMODE, temp);
803}
804
805static void
806i810PrintMode(vgaRegPtr vgaReg, I810RegPtr mode)
807{
808   int i;
809
810   ErrorF("   MiscOut: %x\n", vgaReg->MiscOutReg);
811
812   ErrorF("SEQ: ");
813   for (i = 0; i < vgaReg->numSequencer; i++) {
814      if ((i & 7) == 0)
815	 ErrorF("\n");
816      ErrorF("   %d: %x", i, vgaReg->Sequencer[i]);
817   }
818   ErrorF("\n");
819
820   ErrorF("CRTC: ");
821   for (i = 0; i < vgaReg->numCRTC; i++) {
822      if ((i & 3) == 0)
823	 ErrorF("\n");
824      ErrorF("   %d: %x", i, vgaReg->CRTC[i]);
825   }
826   ErrorF("\n");
827
828   ErrorF("GFX: ");
829   for (i = 0; i < vgaReg->numGraphics; i++) {
830      if ((i & 7) == 0)
831	 ErrorF("\n");
832      ErrorF("   %d: %x", i, vgaReg->Graphics[i]);
833   }
834   ErrorF("\n");
835
836   ErrorF("ATTR: ");
837   for (i = 0; i < vgaReg->numAttribute; i++) {
838      if ((i & 7) == 0)
839	 ErrorF("\n");
840      ErrorF("   %d: %x", i, vgaReg->Attribute[i]);
841   }
842   ErrorF("\n");
843
844   ErrorF("   DisplayControl: %x\n", mode->DisplayControl);
845   ErrorF("   PixelPipeCfg0: %x\n", mode->PixelPipeCfg0);
846   ErrorF("   PixelPipeCfg1: %x\n", mode->PixelPipeCfg1);
847   ErrorF("   PixelPipeCfg2: %x\n", mode->PixelPipeCfg2);
848   ErrorF("   VideoClk2_M: %x\n", mode->VideoClk2_M);
849   ErrorF("   VideoClk2_N: %x\n", mode->VideoClk2_N);
850   ErrorF("   VideoClk2_DivisorSel: %x\n", mode->VideoClk2_DivisorSel);
851   ErrorF("   AddressMapping: %x\n", mode->AddressMapping);
852   ErrorF("   IOControl: %x\n", mode->IOControl);
853   ErrorF("   BitBLTControl: %x\n", mode->BitBLTControl);
854   ErrorF("   ExtVertTotal: %x\n", mode->ExtVertTotal);
855   ErrorF("   ExtVertDispEnd: %x\n", mode->ExtVertDispEnd);
856   ErrorF("   ExtVertSyncStart: %x\n", mode->ExtVertSyncStart);
857   ErrorF("   ExtVertBlankStart: %x\n", mode->ExtVertBlankStart);
858   ErrorF("   ExtHorizTotal: %x\n", mode->ExtHorizTotal);
859   ErrorF("   ExtHorizBlank: %x\n", mode->ExtHorizBlank);
860   ErrorF("   ExtOffset: %x\n", mode->ExtOffset);
861   ErrorF("   InterlaceControl: %x\n", mode->InterlaceControl);
862   ErrorF("   LMI_FIFO_Watermark: %x\n", mode->LMI_FIFO_Watermark);
863   ErrorF("   LprbTail: %x\n", mode->LprbTail);
864   ErrorF("   LprbHead: %x\n", mode->LprbHead);
865   ErrorF("   LprbStart: %x\n", mode->LprbStart);
866   ErrorF("   LprbLen: %x\n", mode->LprbLen);
867}
868
869static void
870DoRestore(ScrnInfoPtr scrn, vgaRegPtr vgaReg, I810RegPtr i810Reg,
871	  Bool restoreFonts)
872{
873   I810Ptr pI810;
874   vgaHWPtr hwp;
875   unsigned char temp;
876   unsigned int itemp;
877   int i;
878
879   pI810 = I810PTR(scrn);
880   hwp = VGAHWPTR(scrn);
881
882   if (I810_DEBUG & DEBUG_VERBOSE_VGA) {
883      ErrorF("Setting mode in I810Restore:\n");
884      i810PrintMode(vgaReg, i810Reg);
885   }
886
887   vgaHWProtect(scrn, TRUE);
888
889   usleep(50000);
890
891   /* Turn off DRAM Refresh */
892   temp = INREG8(DRAM_ROW_CNTL_HI);
893   temp &= ~DRAM_REFRESH_RATE;
894   temp |= DRAM_REFRESH_DISABLE;
895   OUTREG8(DRAM_ROW_CNTL_HI, temp);
896
897   usleep(1000);			/* Wait 1 ms */
898
899   /* Write the M, N and P values */
900   OUTREG16(VCLK2_VCO_M, i810Reg->VideoClk2_M);
901   OUTREG16(VCLK2_VCO_N, i810Reg->VideoClk2_N);
902   OUTREG8(VCLK2_VCO_DIV_SEL, i810Reg->VideoClk2_DivisorSel);
903
904   /*
905    * Turn on 8 bit dac mode, if requested.  This is needed to make
906    * sure that vgaHWRestore writes the values into the DAC properly.
907    * The problem occurs if 8 bit dac mode is requested and the HW is
908    * in 6 bit dac mode.  If this happens, all the values are
909    * automatically shifted left twice by the HW and incorrect colors
910    * will be displayed on the screen.  The only time this can happen
911    * is at server startup time and when switching back from a VT.
912    */
913   temp = INREG8(PIXPIPE_CONFIG_0);
914   temp &= 0x7F;			/* Save all but the 8 bit dac mode bit */
915   temp |= (i810Reg->PixelPipeCfg0 & DAC_8_BIT);
916   OUTREG8(PIXPIPE_CONFIG_0, temp);
917
918   /*
919    * Code to restore any SVGA registers that have been saved/modified
920    * goes here.  Note that it is allowable, and often correct, to
921    * only modify certain bits in a register by a read/modify/write cycle.
922    *
923    * A special case - when using an external clock-setting program,
924    * this function must not change bits associated with the clock
925    * selection.  This condition can be checked by the condition:
926    *
927    *   if (i810Reg->std.NoClock >= 0)
928    *           restore clock-select bits.
929    */
930   if (restoreFonts)
931      vgaHWRestore(scrn, vgaReg, VGA_SR_FONTS | VGA_SR_MODE | VGA_SR_CMAP);
932   else
933      vgaHWRestore(scrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP);
934
935   hwp->writeCrtc(hwp, EXT_VERT_TOTAL, i810Reg->ExtVertTotal);
936   hwp->writeCrtc(hwp, EXT_VERT_DISPLAY, i810Reg->ExtVertDispEnd);
937   hwp->writeCrtc(hwp, EXT_VERT_SYNC_START, i810Reg->ExtVertSyncStart);
938   hwp->writeCrtc(hwp, EXT_VERT_BLANK_START, i810Reg->ExtVertBlankStart);
939   hwp->writeCrtc(hwp, EXT_HORIZ_TOTAL, i810Reg->ExtHorizTotal);
940   hwp->writeCrtc(hwp, EXT_HORIZ_BLANK, i810Reg->ExtHorizBlank);
941   hwp->writeCrtc(hwp, EXT_OFFSET, i810Reg->ExtOffset);
942
943   temp = hwp->readCrtc(hwp, INTERLACE_CNTL);
944   temp &= ~INTERLACE_ENABLE;
945   temp |= i810Reg->InterlaceControl;
946   hwp->writeCrtc(hwp, INTERLACE_CNTL, temp);
947
948   temp = hwp->readGr(hwp, ADDRESS_MAPPING);
949   temp &= 0xE0;			/* Save reserved bits 7:5 */
950   temp |= i810Reg->AddressMapping;
951   hwp->writeGr(hwp, ADDRESS_MAPPING, temp);
952
953   /* Setting the OVRACT Register for video overlay */
954   {
955       uint32_t LCD_TV_Control = INREG(LCD_TV_C);
956       uint32_t TV_HTotal = INREG(LCD_TV_HTOTAL);
957       uint32_t ActiveStart, ActiveEnd;
958
959       if((LCD_TV_Control & LCD_TV_ENABLE)
960	  && !(LCD_TV_Control & LCD_TV_VGAMOD)
961	   && TV_HTotal) {
962	   ActiveStart = ((TV_HTotal >> 16) & 0xfff) - 31;
963	   ActiveEnd = (TV_HTotal & 0x3ff) - 31;
964       } else {
965	   ActiveStart = i810Reg->OverlayActiveStart;
966	   ActiveEnd = i810Reg->OverlayActiveEnd;
967       }
968       OUTREG(LCD_TV_OVRACT,
969	      (ActiveEnd << 16) | ActiveStart);
970   }
971
972   /* Turn on DRAM Refresh */
973   temp = INREG8(DRAM_ROW_CNTL_HI);
974   temp &= ~DRAM_REFRESH_RATE;
975   temp |= DRAM_REFRESH_60HZ;
976   OUTREG8(DRAM_ROW_CNTL_HI, temp);
977
978   temp = INREG8(BITBLT_CNTL);
979   temp &= ~COLEXP_MODE;
980   temp |= i810Reg->BitBLTControl;
981   OUTREG8(BITBLT_CNTL, temp);
982
983   temp = INREG8(DISPLAY_CNTL);
984   temp &= ~(VGA_WRAP_MODE | GUI_MODE);
985   temp |= i810Reg->DisplayControl;
986   OUTREG8(DISPLAY_CNTL, temp);
987
988   temp = INREG8(PIXPIPE_CONFIG_0);
989   temp &= 0x64;			/* Save reserved bits 6:5,2 */
990   temp |= i810Reg->PixelPipeCfg0;
991   OUTREG8(PIXPIPE_CONFIG_0, temp);
992
993   temp = INREG8(PIXPIPE_CONFIG_2);
994   temp &= 0xF3;			/* Save reserved bits 7:4,1:0 */
995   temp |= i810Reg->PixelPipeCfg2;
996   OUTREG8(PIXPIPE_CONFIG_2, temp);
997
998   temp = INREG8(PIXPIPE_CONFIG_1);
999   temp &= ~DISPLAY_COLOR_MODE;
1000   temp &= 0xEF;			/* Restore the CRT control bit */
1001   temp |= i810Reg->PixelPipeCfg1;
1002   OUTREG8(PIXPIPE_CONFIG_1, temp);
1003
1004   OUTREG16(EIR, 0);
1005
1006   itemp = INREG(FWATER_BLC);
1007   itemp &= ~(LM_BURST_LENGTH | LM_FIFO_WATERMARK |
1008	      MM_BURST_LENGTH | MM_FIFO_WATERMARK);
1009   itemp |= i810Reg->LMI_FIFO_Watermark;
1010   OUTREG(FWATER_BLC, itemp);
1011
1012   for (i = 0; i < 8; i++) {
1013      OUTREG(FENCE + i * 4, i810Reg->Fence[i]);
1014      if (I810_DEBUG & DEBUG_VERBOSE_VGA)
1015	 ErrorF("Fence Register : %x\n", i810Reg->Fence[i]);
1016   }
1017
1018   /* First disable the ring buffer (Need to wait for empty first?, if so
1019    * should probably do it before entering this section)
1020    */
1021   itemp = INREG(LP_RING + RING_LEN);
1022   itemp &= ~RING_VALID_MASK;
1023   OUTREG(LP_RING + RING_LEN, itemp);
1024
1025   /* Set up the low priority ring buffer.
1026    */
1027   OUTREG(LP_RING + RING_TAIL, 0);
1028   OUTREG(LP_RING + RING_HEAD, 0);
1029
1030   pI810->LpRing->head = 0;
1031   pI810->LpRing->tail = 0;
1032
1033   itemp = INREG(LP_RING + RING_START);
1034   itemp &= ~(START_ADDR);
1035   itemp |= i810Reg->LprbStart;
1036   OUTREG(LP_RING + RING_START, itemp);
1037
1038   itemp = INREG(LP_RING + RING_LEN);
1039   itemp &= ~(RING_NR_PAGES | RING_REPORT_MASK | RING_VALID_MASK);
1040   itemp |= i810Reg->LprbLen;
1041   OUTREG(LP_RING + RING_LEN, itemp);
1042
1043   if (!(vgaReg->Attribute[0x10] & 0x1)) {
1044      usleep(50000);
1045      if (restoreFonts)
1046	 vgaHWRestore(scrn, vgaReg,
1047		      VGA_SR_FONTS | VGA_SR_MODE | VGA_SR_CMAP);
1048      else
1049	 vgaHWRestore(scrn, vgaReg, VGA_SR_MODE | VGA_SR_CMAP);
1050   }
1051
1052   vgaHWProtect(scrn, FALSE);
1053
1054   temp = hwp->readCrtc(hwp, IO_CTNL);
1055   temp &= ~(EXTENDED_ATTR_CNTL | EXTENDED_CRTC_CNTL);
1056   temp |= i810Reg->IOControl;
1057   hwp->writeCrtc(hwp, IO_CTNL, temp);
1058}
1059
1060static void
1061I810SetRingRegs(ScrnInfoPtr scrn)
1062{
1063   unsigned int itemp;
1064   I810Ptr pI810 = I810PTR(scrn);
1065
1066   OUTREG(LP_RING + RING_TAIL, 0);
1067   OUTREG(LP_RING + RING_HEAD, 0);
1068
1069   itemp = INREG(LP_RING + RING_START);
1070   itemp &= ~(START_ADDR);
1071   itemp |= pI810->LpRing->mem.Start;
1072   OUTREG(LP_RING + RING_START, itemp);
1073
1074   itemp = INREG(LP_RING + RING_LEN);
1075   itemp &= ~(RING_NR_PAGES | RING_REPORT_MASK | RING_VALID_MASK);
1076   itemp |= ((pI810->LpRing->mem.Size - 4096) | RING_NO_REPORT | RING_VALID);
1077   OUTREG(LP_RING + RING_LEN, itemp);
1078}
1079
1080static void
1081I810Restore(ScrnInfoPtr scrn)
1082{
1083   vgaHWPtr hwp;
1084   I810Ptr pI810;
1085
1086   hwp = VGAHWPTR(scrn);
1087   pI810 = I810PTR(scrn);
1088
1089   DoRestore(scrn, &hwp->SavedReg, &pI810->SavedReg, TRUE);
1090}
1091
1092/*
1093 * I810CalcVCLK --
1094 *
1095 * Determine the closest clock frequency to the one requested.
1096 */
1097
1098#define MAX_VCO_FREQ 600.0
1099#define TARGET_MAX_N 30
1100#define REF_FREQ 24.0
1101
1102#define CALC_VCLK(m,n,p) \
1103    (double)m / ((double)n * (1 << p)) * 4 * REF_FREQ
1104
1105static void
1106I810CalcVCLK(ScrnInfoPtr scrn, double freq)
1107{
1108   I810Ptr pI810 = I810PTR(scrn);
1109   I810RegPtr i810Reg = &pI810->ModeReg;
1110   int m, n, p;
1111   double f_out;
1112   double f_err;
1113   double f_vco;
1114   int m_best = 0, n_best = 0, p_best = 0;
1115   double f_target = freq;
1116   double err_max = 0.005;
1117   double err_target = 0.001;
1118   double err_best = 999999.0;
1119
1120   p_best = p = log(MAX_VCO_FREQ / f_target) / log((double)2);
1121   /* Make sure p is within range. */
1122   if (p_best > 5) {
1123      p_best = p = 5;
1124   }
1125
1126   f_vco = f_target * (1 << p);
1127
1128   n = 2;
1129   do {
1130      n++;
1131      m = f_vco / (REF_FREQ / (double)n) / (double)4.0 + 0.5;
1132      if (m < 3)
1133	 m = 3;
1134      f_out = CALC_VCLK(m, n, p);
1135      f_err = 1.0 - (f_target / f_out);
1136      if (fabs(f_err) < err_max) {
1137	 m_best = m;
1138	 n_best = n;
1139	 err_best = f_err;
1140      }
1141   } while ((fabs(f_err) >= err_target) &&
1142	    ((n <= TARGET_MAX_N) || (fabs(err_best) > err_max)));
1143
1144   if (fabs(f_err) < err_target) {
1145      m_best = m;
1146      n_best = n;
1147   }
1148
1149   i810Reg->VideoClk2_M = (m_best - 2) & 0x3FF;
1150   i810Reg->VideoClk2_N = (n_best - 2) & 0x3FF;
1151   i810Reg->VideoClk2_DivisorSel = (p_best << 4);
1152
1153   xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, 3,
1154		  "Setting dot clock to %.1f MHz " "[ 0x%x 0x%x 0x%x ] "
1155		  "[ %d %d %d ]\n", CALC_VCLK(m_best, n_best, p_best),
1156		  i810Reg->VideoClk2_M, i810Reg->VideoClk2_N,
1157		  i810Reg->VideoClk2_DivisorSel, m_best, n_best, p_best);
1158}
1159
1160static Bool
1161I810SetMode(ScrnInfoPtr scrn, DisplayModePtr mode)
1162{
1163   I810Ptr pI810 = I810PTR(scrn);
1164   I810RegPtr i810Reg = &pI810->ModeReg;
1165   vgaRegPtr pVga = &VGAHWPTR(scrn)->ModeReg;
1166   double dclk = mode->Clock / 1000.0;
1167
1168   switch (scrn->bitsPerPixel) {
1169   case 8:
1170      pVga->CRTC[0x13] = scrn->displayWidth >> 3;
1171      i810Reg->ExtOffset = scrn->displayWidth >> 11;
1172      i810Reg->PixelPipeCfg1 = DISPLAY_8BPP_MODE;
1173      i810Reg->BitBLTControl = COLEXP_8BPP;
1174      break;
1175   case 16:
1176      if (scrn->weight.green == 5) {
1177	 i810Reg->PixelPipeCfg1 = DISPLAY_15BPP_MODE;
1178      } else {
1179	 i810Reg->PixelPipeCfg1 = DISPLAY_16BPP_MODE;
1180      }
1181      pVga->CRTC[0x13] = scrn->displayWidth >> 2;
1182      i810Reg->ExtOffset = scrn->displayWidth >> 10;
1183      i810Reg->BitBLTControl = COLEXP_16BPP;
1184
1185      /* Enable Palette Programming for Direct Color visuals. -jens */
1186      i810Reg->PixelPipeCfg2 = DISPLAY_GAMMA_ENABLE;
1187      break;
1188   case 24:
1189      pVga->CRTC[0x13] = (scrn->displayWidth * 3) >> 3;
1190      i810Reg->ExtOffset = (scrn->displayWidth * 3) >> 11;
1191
1192      i810Reg->PixelPipeCfg1 = DISPLAY_24BPP_MODE;
1193      i810Reg->BitBLTControl = COLEXP_24BPP;
1194
1195      /* Enable Palette Programming for Direct Color visuals. -jens */
1196      i810Reg->PixelPipeCfg2 = DISPLAY_GAMMA_ENABLE;
1197      break;
1198   default:
1199      break;
1200   }
1201
1202   /* Turn on 8 bit dac if requested */
1203   if (xf86ReturnOptValBool(pI810->Options, OPTION_DAC_6BIT, FALSE))
1204      i810Reg->PixelPipeCfg0 = DAC_6_BIT;
1205   else
1206      i810Reg->PixelPipeCfg0 = DAC_8_BIT;
1207
1208   /* Do not delay CRT Blank: needed for video overlay */
1209   i810Reg->PixelPipeCfg1 |= 0x10;
1210
1211   /* Turn on Extended VGA Interpretation */
1212   i810Reg->IOControl = EXTENDED_CRTC_CNTL;
1213
1214   /* Turn on linear and page mapping */
1215   i810Reg->AddressMapping = (LINEAR_MODE_ENABLE | GTT_MEM_MAP_ENABLE);
1216
1217   /* Turn on GUI mode */
1218   i810Reg->DisplayControl = HIRES_MODE;
1219
1220   /* Calculate the extended CRTC regs */
1221   i810Reg->ExtVertTotal = (mode->CrtcVTotal - 2) >> 8;
1222   i810Reg->ExtVertDispEnd = (mode->CrtcVDisplay - 1) >> 8;
1223   i810Reg->ExtVertSyncStart = mode->CrtcVSyncStart >> 8;
1224   i810Reg->ExtVertBlankStart = mode->CrtcVBlankStart >> 8;
1225   i810Reg->ExtHorizTotal = ((mode->CrtcHTotal >> 3) - 5) >> 8;
1226   i810Reg->ExtHorizBlank = (((mode->CrtcHBlankEnd >> 3) - 1) & 0x40) >> 6;
1227
1228   /*
1229    * the KGA fix in vgaHW.c results in the first
1230    * scanline and the first character clock (8 pixels)
1231    * of each scanline thereafter on display with an i810
1232    * to be blank. Restoring CRTC 3, 5, & 22 to their
1233    * "theoretical" values corrects the problem. KAO.
1234    */
1235   pVga->CRTC[3] = (((mode->CrtcHBlankEnd >> 3) - 1) & 0x1F) | 0x80;
1236   pVga->CRTC[5] = ((((mode->CrtcHBlankEnd >> 3) - 1) & 0x20) << 2)
1237	 | (((mode->CrtcHSyncEnd >> 3)) & 0x1F);
1238   pVga->CRTC[22] = (mode->CrtcVBlankEnd - 1) & 0xFF;
1239
1240   i810Reg->ExtHorizBlank = vgaHWHBlankKGA(mode, pVga, 7, 0);
1241   vgaHWVBlankKGA(mode, pVga, 8, 0);
1242
1243   /*
1244    * The following workarounds are needed to get video overlay working
1245    * at 1024x768 and 1280x1024 display resolutions.
1246    */
1247   if ((mode->CrtcVDisplay == 768) && (i810Reg->ExtVertBlankStart == 3)) {
1248      i810Reg->ExtVertBlankStart = 2;
1249   }
1250   if ((mode->CrtcVDisplay == 1024) && (i810Reg->ExtVertBlankStart == 4)) {
1251      i810Reg->ExtVertBlankStart = 3;
1252   }
1253
1254   /* OVRACT Register */
1255   i810Reg->OverlayActiveStart = mode->CrtcHTotal - 32;
1256   i810Reg->OverlayActiveEnd = mode->CrtcHDisplay - 32;
1257
1258   /* Turn on interlaced mode if necessary */
1259   if (mode->Flags & V_INTERLACE) {
1260      i810Reg->InterlaceControl = INTERLACE_ENABLE;
1261      i810Reg->ExtVertDispEnd *= 2;
1262   } else
1263      i810Reg->InterlaceControl = INTERLACE_DISABLE;
1264
1265   /*
1266    * Set the overscan color to 0.
1267    * NOTE: This only affects >8bpp mode.
1268    */
1269   pVga->Attribute[0x11] = 0;
1270
1271   /*
1272    * Calculate the VCLK that most closely matches the requested dot
1273    * clock.
1274    */
1275   I810CalcVCLK(scrn, dclk);
1276
1277   /* Since we program the clocks ourselves, always use VCLK2. */
1278   pVga->MiscOutReg |= 0x0C;
1279
1280   /* Calculate the FIFO Watermark and Burst Length. */
1281   i810Reg->LMI_FIFO_Watermark = I810CalcWatermark(scrn, dclk, FALSE);
1282
1283   /* Setup the ring buffer */
1284   i810Reg->LprbTail = 0;
1285   i810Reg->LprbHead = 0;
1286   i810Reg->LprbStart = pI810->LpRing->mem.Start;
1287
1288   if (i810Reg->LprbStart)
1289      i810Reg->LprbLen = ((pI810->LpRing->mem.Size - 4096) |
1290			  RING_NO_REPORT | RING_VALID);
1291   else
1292      i810Reg->LprbLen = RING_INVALID;
1293
1294   return TRUE;
1295}
1296
1297static Bool
1298I810ModeInit(ScrnInfoPtr scrn, DisplayModePtr mode)
1299{
1300   vgaHWPtr hwp;
1301   I810Ptr pI810;
1302
1303   hwp = VGAHWPTR(scrn);
1304   pI810 = I810PTR(scrn);
1305
1306   vgaHWUnlock(hwp);
1307
1308   if (!vgaHWInit(scrn, mode))
1309      return FALSE;
1310
1311   scrn->vtSema = TRUE;
1312
1313   if (!I810SetMode(scrn, mode))
1314      return FALSE;
1315
1316#ifdef HAVE_DRI1
1317   if (pI810->directRenderingEnabled) {
1318      DRILock(xf86ScrnToScreen(scrn), 0);
1319      pI810->LockHeld = 1;
1320   }
1321#endif
1322
1323   DoRestore(scrn, &hwp->ModeReg, &pI810->ModeReg, FALSE);
1324
1325#ifdef HAVE_DRI1
1326   if (pI810->directRenderingEnabled) {
1327      DRIUnlock(xf86ScrnToScreen(scrn));
1328      pI810->LockHeld = 0;
1329   }
1330#endif
1331
1332   return TRUE;
1333}
1334
1335static void
1336I810LoadPalette15(ScrnInfoPtr scrn, int numColors, int *indices,
1337		  LOCO * colors, VisualPtr pVisual)
1338{
1339   vgaHWPtr hwp;
1340   int i, j, index;
1341   unsigned char r, g, b;
1342
1343   hwp = VGAHWPTR(scrn);
1344
1345   for (i = 0; i < numColors; i++) {
1346      index = indices[i];
1347      r = colors[index].red;
1348      g = colors[index].green;
1349      b = colors[index].blue;
1350      for (j = 0; j < 8; j++) {
1351	 hwp->writeDacWriteAddr(hwp, (index << 3) + j);
1352	 hwp->writeDacData(hwp, r);
1353	 hwp->writeDacData(hwp, g);
1354	 hwp->writeDacData(hwp, b);
1355      }
1356   }
1357}
1358
1359static void
1360I810LoadPalette16(ScrnInfoPtr scrn, int numColors, int *indices,
1361		  LOCO * colors, VisualPtr pVisual)
1362{
1363   vgaHWPtr hwp;
1364   int i, index;
1365   unsigned char r, g, b;
1366
1367   hwp = VGAHWPTR(scrn);
1368
1369   /* Load all four entries in each of the 64 color ranges.  -jens */
1370   for (i = 0; i < numColors; i++) {
1371      index = indices[i / 2];
1372      r = colors[index].red;
1373      b = colors[index].blue;
1374      index = indices[i];
1375      g = colors[index].green;
1376
1377      hwp->writeDacWriteAddr(hwp, index << 2);
1378      hwp->writeDacData(hwp, r);
1379      hwp->writeDacData(hwp, g);
1380      hwp->writeDacData(hwp, b);
1381
1382      hwp->writeDacWriteAddr(hwp, (index << 2) + 1);
1383      hwp->writeDacData(hwp, r);
1384      hwp->writeDacData(hwp, g);
1385      hwp->writeDacData(hwp, b);
1386
1387      hwp->writeDacWriteAddr(hwp, (index << 2) + 2);
1388      hwp->writeDacData(hwp, r);
1389      hwp->writeDacData(hwp, g);
1390      hwp->writeDacData(hwp, b);
1391
1392      hwp->writeDacWriteAddr(hwp, (index << 2) + 3);
1393      hwp->writeDacData(hwp, r);
1394      hwp->writeDacData(hwp, g);
1395      hwp->writeDacData(hwp, b);
1396
1397      i++;
1398      index = indices[i];
1399      g = colors[index].green;
1400
1401      hwp->writeDacWriteAddr(hwp, index << 2);
1402      hwp->writeDacData(hwp, r);
1403      hwp->writeDacData(hwp, g);
1404      hwp->writeDacData(hwp, b);
1405
1406      hwp->writeDacWriteAddr(hwp, (index << 2) + 1);
1407      hwp->writeDacData(hwp, r);
1408      hwp->writeDacData(hwp, g);
1409      hwp->writeDacData(hwp, b);
1410
1411      hwp->writeDacWriteAddr(hwp, (index << 2) + 2);
1412      hwp->writeDacData(hwp, r);
1413      hwp->writeDacData(hwp, g);
1414      hwp->writeDacData(hwp, b);
1415
1416      hwp->writeDacWriteAddr(hwp, (index << 2) + 3);
1417      hwp->writeDacData(hwp, r);
1418      hwp->writeDacData(hwp, g);
1419      hwp->writeDacData(hwp, b);
1420   }
1421}
1422
1423static void
1424I810LoadPalette24(ScrnInfoPtr scrn, int numColors, int *indices,
1425		  LOCO * colors, VisualPtr pVisual)
1426{
1427   vgaHWPtr hwp;
1428   int i, index;
1429   unsigned char r, g, b;
1430
1431   hwp = VGAHWPTR(scrn);
1432
1433   for (i = 0; i < numColors; i++) {
1434      index = indices[i];
1435      r = colors[index].red;
1436      g = colors[index].green;
1437      b = colors[index].blue;
1438      hwp->writeDacWriteAddr(hwp, index);
1439      hwp->writeDacData(hwp, r);
1440      hwp->writeDacData(hwp, g);
1441      hwp->writeDacData(hwp, b);
1442   }
1443}
1444
1445Bool
1446I810AllocateFront(ScrnInfoPtr scrn)
1447{
1448   I810Ptr pI810 = I810PTR(scrn);
1449   int cache_lines = -1;
1450
1451   if (pI810->DoneFrontAlloc)
1452      return TRUE;
1453
1454   memset(&(pI810->FbMemBox), 0, sizeof(BoxRec));
1455   /* Alloc FrontBuffer/Ring/Accel memory */
1456   pI810->FbMemBox.x1 = 0;
1457   pI810->FbMemBox.x2 = scrn->displayWidth;
1458   pI810->FbMemBox.y1 = 0;
1459   pI810->FbMemBox.y2 = scrn->virtualY;
1460
1461   xf86GetOptValInteger(pI810->Options, OPTION_CACHE_LINES, &cache_lines);
1462
1463   if (cache_lines < 0) {
1464      /* make sure there is enough for two DVD sized YUV buffers */
1465      cache_lines = (scrn->depth == 24) ? 256 : 384;
1466      if (scrn->displayWidth <= 1024)
1467	 cache_lines *= 2;
1468   }
1469   /* Make sure there's enough space for cache_lines.
1470    *
1471    * Had a bug here where maxCacheLines was computed to be less than 0.
1472    * Not sure why 256 was initially subtracted from videoRam in the
1473    * maxCacheLines calculation, but that was causing a problem
1474    * for configurations that have exactly enough Ram for the framebuffer.
1475    * Common code should catch the case where there isn't enough space for
1476    * framebuffer, we'll just check for no space for cache_lines.  -jens
1477    *
1478    */
1479   {
1480      int maxCacheLines;
1481
1482      maxCacheLines = (scrn->videoRam * 1024 /
1483		       (scrn->bitsPerPixel / 8) /
1484		       scrn->displayWidth) - scrn->virtualY;
1485      if (maxCacheLines < 0)
1486	 maxCacheLines = 0;
1487      if (cache_lines > maxCacheLines)
1488	 cache_lines = maxCacheLines;
1489   }
1490   pI810->FbMemBox.y2 += cache_lines;
1491
1492   xf86DrvMsg(scrn->scrnIndex, X_INFO,
1493	      "Adding %i scanlines for pixmap caching\n", cache_lines);
1494
1495   /* Reserve room for the framebuffer and pixcache.  Put at the top
1496    * of memory so we can have nice alignment for the tiled regions at
1497    * the start of memory.
1498    */
1499
1500   if (!I810AllocLow(&(pI810->FrontBuffer),
1501		     &(pI810->SysMem),
1502		     ALIGN((pI810->FbMemBox.x2 * pI810->FbMemBox.y2 * pI810->cpp), 4096))) {
1503      xf86DrvMsg(scrn->scrnIndex,
1504		 X_WARNING, "Framebuffer allocation failed\n");
1505      return FALSE;
1506   }
1507
1508   memset(pI810->LpRing, 0, sizeof(I810RingBuffer));
1509   if (I810AllocLow(&(pI810->LpRing->mem), &(pI810->SysMem), 16 * 4096)) {
1510      pI810->LpRing->tail_mask = pI810->LpRing->mem.Size - 1;
1511      pI810->LpRing->virtual_start = pI810->FbBase + pI810->LpRing->mem.Start;
1512      pI810->LpRing->head = 0;
1513      pI810->LpRing->tail = 0;
1514      pI810->LpRing->space = 0;
1515   } else {
1516      xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1517		 "Ring buffer allocation failed\n");
1518      return (FALSE);
1519   }
1520
1521   if (I810AllocLow(&pI810->Scratch, &(pI810->SysMem), 64 * 1024) ||
1522       I810AllocLow(&pI810->Scratch, &(pI810->SysMem), 16 * 1024)) {
1523      xf86DrvMsg(scrn->scrnIndex, X_INFO, "Allocated Scratch Memory\n");
1524   } else {
1525      xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1526		 "Scratch memory allocation failed\n");
1527      return (FALSE);
1528   }
1529
1530   pI810->DoneFrontAlloc = TRUE;
1531   return TRUE;
1532}
1533
1534static Bool
1535I810ScreenInit(SCREEN_INIT_ARGS_DECL)
1536{
1537   ScrnInfoPtr scrn;
1538   vgaHWPtr hwp;
1539   I810Ptr pI810;
1540   VisualPtr visual;
1541
1542   scrn = xf86ScreenToScrn(screen);
1543   pI810 = I810PTR(scrn);
1544   hwp = VGAHWPTR(scrn);
1545
1546   pI810->LpRing = calloc(sizeof(I810RingBuffer),1);
1547   if (!pI810->LpRing) {
1548     xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1549		"Could not allocate lpring data structure.\n");
1550     return FALSE;
1551   }
1552
1553   miClearVisualTypes();
1554
1555   /* Re-implemented Direct Color support, -jens */
1556   if (!miSetVisualTypes(scrn->depth, miGetDefaultVisualMask(scrn->depth),
1557			 scrn->rgbBits, scrn->defaultVisual))
1558      return FALSE;
1559
1560   if (!miSetPixmapDepths())
1561      return FALSE;
1562
1563   {
1564      I810RegPtr i810Reg = &pI810->ModeReg;
1565      int i;
1566
1567      for (i = 0; i < 8; i++)
1568	 i810Reg->Fence[i] = 0;
1569   }
1570
1571   /* Have to init the DRM earlier than in other drivers to get agp
1572    * memory.  Wonder if this is going to be a problem...
1573    */
1574
1575#ifdef HAVE_DRI1
1576   /*
1577    * Setup DRI after visuals have been established, but before fbScreenInit
1578    * is called.   fbScreenInit will eventually call into the drivers
1579    * InitGLXVisuals call back.
1580    */
1581   /*
1582    * pI810->directRenderingDisabled is set once in PreInit.  Reinitialise
1583    * pI810->directRenderingEnabled based on it each generation.
1584    */
1585   pI810->directRenderingEnabled = !pI810->directRenderingDisabled;
1586
1587   if (pI810->directRenderingEnabled==TRUE)
1588     pI810->directRenderingEnabled = I810DRIScreenInit(screen);
1589
1590#else
1591   pI810->directRenderingEnabled = FALSE;
1592   if (!I810AllocateGARTMemory(scrn))
1593      return FALSE;
1594   if (!I810AllocateFront(scrn))
1595      return FALSE;
1596#endif
1597
1598   if (!I810MapMem(scrn))
1599      return FALSE;
1600
1601   scrn->memPhysBase = (unsigned long)pI810->LinearAddr;
1602   scrn->fbOffset = 0;
1603
1604   vgaHWSetMmioFuncs(hwp, pI810->MMIOBase, 0);
1605   vgaHWGetIOBase(hwp);
1606   if (!vgaHWMapMem(scrn))
1607      return FALSE;
1608
1609   I810Save(scrn);
1610   if (!I810ModeInit(scrn, scrn->currentMode))
1611      return FALSE;
1612
1613   I810SaveScreen(screen, FALSE);
1614   I810AdjustFrame(ADJUST_FRAME_ARGS(scrn, scrn->frameX0, scrn->frameY0));
1615
1616   if (!fbScreenInit(screen, pI810->FbBase + scrn->fbOffset,
1617		     scrn->virtualX, scrn->virtualY,
1618		     scrn->xDpi, scrn->yDpi,
1619		     scrn->displayWidth, scrn->bitsPerPixel))
1620      return FALSE;
1621
1622   if (scrn->bitsPerPixel > 8) {
1623      /* Fixup RGB ordering */
1624      visual = screen->visuals + screen->numVisuals;
1625      while (--visual >= screen->visuals) {
1626	 if ((visual->class | DynamicClass) == DirectColor) {
1627	    visual->offsetRed = scrn->offset.red;
1628	    visual->offsetGreen = scrn->offset.green;
1629	    visual->offsetBlue = scrn->offset.blue;
1630	    visual->redMask = scrn->mask.red;
1631	    visual->greenMask = scrn->mask.green;
1632	    visual->blueMask = scrn->mask.blue;
1633	 }
1634      }
1635   }
1636
1637   fbPictureInit(screen, NULL, 0);
1638
1639   xf86SetBlackWhitePixels(screen);
1640
1641#ifdef HAVE_DRI1
1642   if (pI810->LpRing->mem.Start == 0 && pI810->directRenderingEnabled) {
1643      pI810->directRenderingEnabled = FALSE;
1644      I810DRICloseScreen(screen);
1645   }
1646
1647   if (!pI810->directRenderingEnabled) {
1648      pI810->DoneFrontAlloc = FALSE;
1649      if (!I810AllocateGARTMemory(scrn))
1650	 return FALSE;
1651      if (!I810AllocateFront(scrn))
1652	 return FALSE;
1653   }
1654#endif
1655
1656#ifdef HAVE_DGAPROC_H
1657   I810DGAInit(screen);
1658#endif
1659
1660   if (!xf86InitFBManager(screen, &(pI810->FbMemBox))) {
1661      xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1662		 "Failed to init memory manager\n");
1663      return FALSE;
1664   }
1665
1666   if (pI810->LpRing->mem.Size != 0) {
1667      I810SetRingRegs(scrn);
1668
1669      if (!pI810->noAccel && !I810AccelInit(screen)) {
1670	 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1671		    "Hardware acceleration initialization failed\n");
1672      }
1673
1674      I810EmitFlush(scrn);
1675   }
1676
1677   xf86SetBackingStore(screen);
1678   xf86SetSilkenMouse(screen);
1679
1680   miDCInitialize(screen, xf86GetPointerScreenFuncs());
1681
1682   if (!xf86ReturnOptValBool(pI810->Options, OPTION_SW_CURSOR, FALSE)) {
1683      if (!I810CursorInit(screen)) {
1684	 xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1685		    "Hardware cursor initialization failed\n");
1686      }
1687   }
1688
1689   if (!miCreateDefColormap(screen))
1690      return FALSE;
1691
1692   /* Use driver specific palette load routines for Direct Color support. -jens */
1693   if (scrn->bitsPerPixel == 16) {
1694      if (scrn->depth == 15) {
1695	 if (!xf86HandleColormaps(screen, 256, 8, I810LoadPalette15, NULL,
1696				  CMAP_PALETTED_TRUECOLOR |
1697				  CMAP_RELOAD_ON_MODE_SWITCH))
1698	    return FALSE;
1699      } else {
1700	 if (!xf86HandleColormaps(screen, 256, 8, I810LoadPalette16, NULL,
1701				  CMAP_PALETTED_TRUECOLOR |
1702				  CMAP_RELOAD_ON_MODE_SWITCH))
1703	    return FALSE;
1704      }
1705   } else {
1706      if (!xf86HandleColormaps(screen, 256, 8, I810LoadPalette24, NULL,
1707			       CMAP_PALETTED_TRUECOLOR |
1708			       CMAP_RELOAD_ON_MODE_SWITCH))
1709	 return FALSE;
1710   }
1711
1712   xf86DPMSInit(screen, I810DisplayPowerManagementSet, 0);
1713
1714   I810InitVideo(screen);
1715
1716#ifdef HAVE_DRI1
1717   if (pI810->directRenderingEnabled) {
1718      /* Now that mi, fb, drm and others have done their thing,
1719       * complete the DRI setup.
1720       */
1721      pI810->directRenderingEnabled = I810DRIFinishScreenInit(screen);
1722   }
1723#ifdef XvMCExtension
1724   if ((pI810->directRenderingEnabled) && (pI810->numSurfaces)) {
1725      /* Initialize the hardware motion compensation code */
1726      I810InitMC(screen);
1727   }
1728#endif
1729#endif
1730
1731   if (pI810->directRenderingEnabled) {
1732      xf86DrvMsg(scrn->scrnIndex, X_INFO, "Direct rendering enabled\n");
1733   } else {
1734      xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Direct rendering disabled\n");
1735   }
1736
1737   screen->SaveScreen = I810SaveScreen;
1738   pI810->CloseScreen = screen->CloseScreen;
1739   screen->CloseScreen = I810CloseScreen;
1740
1741   if (serverGeneration == 1)
1742      xf86ShowUnusedOptions(scrn->scrnIndex, scrn->options);
1743
1744   return TRUE;
1745}
1746
1747Bool
1748I810SwitchMode(SWITCH_MODE_ARGS_DECL)
1749{
1750   SCRN_INFO_PTR(arg);
1751#if 0
1752   I810Ptr pI810 = I810PTR(scrn);
1753#endif
1754   if (I810_DEBUG & DEBUG_VERBOSE_CURSOR)
1755      ErrorF("I810SwitchMode %p\n", (void *)mode);
1756
1757#if 0
1758/*
1759 * This has been added to prevent lockups on mode switch by modeling
1760 * it after I810Leave()/I810Enter() but the call to I810DRILeave()
1761 * was missing so it caused the opposite.
1762 * The version below works but it is doubtful it does any good.
1763 * If lockups on mode switch are still seen revisit this code. (EE)
1764 */
1765
1766# ifdef HAVE_DRI1
1767   if (pI810->directRenderingEnabled) {
1768      if (I810_DEBUG & DEBUG_VERBOSE_DRI)
1769	 ErrorF("calling dri lock\n");
1770      DRILock(screenInfo.screens[scrnIndex], 0);
1771      pI810->LockHeld = 1;
1772   }
1773# endif
1774   if (pI810->AccelInfoRec != NULL) {
1775      I810RefreshRing(scrn);
1776      I810Sync(scrn);
1777      pI810->AccelInfoRec->NeedToSync = FALSE;
1778   }
1779   I810Restore(scrn);
1780
1781# ifdef HAVE_DRI1
1782   if (pI810->directRenderingEnabled) {
1783       if (!I810DRILeave(scrn))
1784	   return FALSE;
1785       if (!I810DRIEnter(scrn))
1786	   return FALSE;
1787
1788       if (I810_DEBUG & DEBUG_VERBOSE_DRI)
1789	   ErrorF("calling dri unlock\n");
1790       DRIUnlock(screenInfo.screens[scrnIndex]);
1791       pI810->LockHeld = 0;
1792   }
1793# endif
1794#endif
1795   return I810ModeInit(scrn, mode);
1796}
1797
1798void
1799I810AdjustFrame(ADJUST_FRAME_ARGS_DECL)
1800{
1801   SCRN_INFO_PTR(arg);
1802   I810Ptr pI810 = I810PTR(scrn);
1803   vgaHWPtr hwp = VGAHWPTR(scrn);
1804   int Base;
1805
1806#if 1
1807   if (pI810->showCache) {
1808     int lastline = pI810->FbMapSize /
1809       ((scrn->displayWidth * scrn->bitsPerPixel) / 8);
1810     lastline -= scrn->currentMode->VDisplay;
1811     if (y > 0)
1812       y += scrn->currentMode->VDisplay;
1813     if (y > lastline) y = lastline;
1814   }
1815#endif
1816   Base = (y * scrn->displayWidth + x) >> 2;
1817
1818   if (I810_DEBUG & DEBUG_VERBOSE_CURSOR)
1819      ErrorF("I810AdjustFrame %d,%d\n", x, y);
1820
1821   switch (scrn->bitsPerPixel) {
1822   case 8:
1823      break;
1824   case 16:
1825      Base *= 2;
1826      break;
1827   case 24:
1828      /* KW: Need to do 16-pixel alignment for i810, otherwise you
1829       * get bad watermark problems.  Need to fixup the mouse
1830       * pointer positioning to take this into account.
1831       */
1832      pI810->CursorOffset = (Base & 0x3) * 4;
1833      Base &= ~0x3;
1834      Base *= 3;
1835      break;
1836   case 32:
1837      Base *= 4;
1838      break;
1839   }
1840
1841   hwp->writeCrtc(hwp, START_ADDR_LO, Base & 0xFF);
1842   hwp->writeCrtc(hwp, START_ADDR_HI, (Base & 0xFF00) >> 8);
1843   hwp->writeCrtc(hwp, EXT_START_ADDR_HI, (Base & 0x3FC00000) >> 22);
1844   hwp->writeCrtc(hwp, EXT_START_ADDR,
1845		  ((Base & 0x00eF0000) >> 16 | EXT_START_ADDR_ENABLE));
1846}
1847
1848/* These functions are usually called with the lock **not held**.
1849 */
1850static Bool
1851I810EnterVT(VT_FUNC_ARGS_DECL)
1852{
1853   SCRN_INFO_PTR(arg);
1854
1855#ifdef HAVE_DRI1
1856   I810Ptr pI810 = I810PTR(scrn);
1857#endif
1858
1859   if (I810_DEBUG & DEBUG_VERBOSE_DRI)
1860      ErrorF("\n\nENTER VT\n");
1861
1862   if (!I810BindGARTMemory(scrn)) {
1863      return FALSE;
1864   }
1865#ifdef HAVE_DRI1
1866   if (!I810DRIEnter(scrn)) {
1867      return FALSE;
1868   }
1869   if (pI810->directRenderingEnabled) {
1870      if (I810_DEBUG & DEBUG_VERBOSE_DRI)
1871	 ErrorF("calling dri unlock\n");
1872      DRIUnlock(xf86ScrnToScreen(scrn));
1873      pI810->LockHeld = 0;
1874   }
1875#endif
1876
1877   if (!I810ModeInit(scrn, scrn->currentMode))
1878      return FALSE;
1879   I810AdjustFrame(ADJUST_FRAME_ARGS(scrn, scrn->frameX0, scrn->frameY0));
1880   return TRUE;
1881}
1882
1883static void
1884I810LeaveVT(VT_FUNC_ARGS_DECL)
1885{
1886   SCRN_INFO_PTR(arg);
1887   vgaHWPtr hwp = VGAHWPTR(scrn);
1888   I810Ptr pI810 = I810PTR(scrn);
1889
1890   if (I810_DEBUG & DEBUG_VERBOSE_DRI)
1891      ErrorF("\n\n\nLeave VT\n");
1892
1893#ifdef HAVE_DRI1
1894   if (pI810->directRenderingEnabled) {
1895      if (I810_DEBUG & DEBUG_VERBOSE_DRI)
1896	 ErrorF("calling dri lock\n");
1897      DRILock(xf86ScrnToScreen(scrn), 0);
1898      pI810->LockHeld = 1;
1899   }
1900#endif
1901
1902#ifdef HAVE_XAA_H
1903   if (pI810->AccelInfoRec != NULL) {
1904      I810RefreshRing(scrn);
1905      I810Sync(scrn);
1906      pI810->AccelInfoRec->NeedToSync = FALSE;
1907   }
1908#endif
1909   I810Restore(scrn);
1910
1911   if (!I810UnbindGARTMemory(scrn))
1912      return;
1913#ifdef HAVE_DRI1
1914   if (!I810DRILeave(scrn))
1915      return;
1916#endif
1917
1918   vgaHWLock(hwp);
1919}
1920
1921static Bool
1922I810CloseScreen(CLOSE_SCREEN_ARGS_DECL)
1923{
1924   ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1925   vgaHWPtr hwp = VGAHWPTR(scrn);
1926   I810Ptr pI810 = I810PTR(scrn);
1927#ifdef HAVE_XAA_H
1928   XAAInfoRecPtr infoPtr = pI810->AccelInfoRec;
1929#endif
1930
1931   if (scrn->vtSema == TRUE) {
1932#ifdef HAVE_XAA_H
1933      if (pI810->AccelInfoRec != NULL) {
1934	 I810RefreshRing(scrn);
1935	 I810Sync(scrn);
1936	 pI810->AccelInfoRec->NeedToSync = FALSE;
1937      }
1938#endif
1939      I810Restore(scrn);
1940      vgaHWLock(hwp);
1941   }
1942#ifdef HAVE_DRI1
1943   if (pI810->directRenderingEnabled) {
1944      I810DRICloseScreen(screen);
1945      pI810->directRenderingEnabled = FALSE;
1946   }
1947#endif
1948
1949   if (scrn->vtSema == TRUE) {
1950      I810UnbindGARTMemory(scrn);
1951      I810Restore(scrn);
1952      vgaHWLock(hwp);
1953   }
1954
1955   I810UnmapMem(scrn);
1956   vgaHWUnmapMem(scrn);
1957
1958   if (pI810->ScanlineColorExpandBuffers) {
1959      free(pI810->ScanlineColorExpandBuffers);
1960      pI810->ScanlineColorExpandBuffers = NULL;
1961   }
1962
1963#ifdef HAVE_XAA_H
1964   if (infoPtr) {
1965      if (infoPtr->ScanlineColorExpandBuffers)
1966	 free(infoPtr->ScanlineColorExpandBuffers);
1967      XAADestroyInfoRec(infoPtr);
1968      pI810->AccelInfoRec = NULL;
1969   }
1970#endif
1971
1972   if (pI810->CursorInfoRec) {
1973      xf86DestroyCursorInfoRec(pI810->CursorInfoRec);
1974      pI810->CursorInfoRec = NULL;
1975   }
1976
1977   /* Free all allocated video ram.
1978    */
1979   pI810->SysMem = pI810->SavedSysMem;
1980   pI810->DcacheMem = pI810->SavedDcacheMem;
1981   pI810->DoneFrontAlloc = FALSE;
1982
1983   /* Need to actually close the gart fd, or the unbound memory will just sit
1984    * around.  Will prevent the Xserver from recycling.
1985    */
1986   xf86GARTCloseScreen(scrn->scrnIndex);
1987
1988   free(pI810->LpRing);
1989   pI810->LpRing = NULL;
1990
1991   scrn->vtSema = FALSE;
1992   screen->CloseScreen = pI810->CloseScreen;
1993   return (*screen->CloseScreen) (CLOSE_SCREEN_ARGS);
1994}
1995
1996static void
1997I810FreeScreen(FREE_SCREEN_ARGS_DECL)
1998{
1999   SCRN_INFO_PTR(arg);
2000   I810FreeRec(scrn);
2001   if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
2002     vgaHWFreeHWRec(scrn);
2003}
2004
2005static ModeStatus
2006I810ValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode, Bool verbose, int flags)
2007{
2008   SCRN_INFO_PTR(arg);
2009   if (mode->Flags & V_INTERLACE) {
2010      if (verbose) {
2011	 xf86DrvMsg(scrn->scrnIndex, X_PROBED,
2012		    "Removing interlaced mode \"%s\"\n", mode->name);
2013      }
2014      return MODE_BAD;
2015   }
2016   return MODE_OK;
2017}
2018
2019static Bool
2020I810SaveScreen(ScreenPtr screen, Bool unblack)
2021{
2022   return vgaHWSaveScreen(screen, unblack);
2023}
2024
2025static void
2026I810DisplayPowerManagementSet(ScrnInfoPtr scrn, int PowerManagementMode,
2027			      int flags)
2028{
2029   I810Ptr pI810;
2030   unsigned char SEQ01 = 0;
2031   int DPMSSyncSelect = 0;
2032   vgaHWPtr hwp;
2033
2034   pI810 = I810PTR(scrn);
2035   switch (PowerManagementMode) {
2036   case DPMSModeOn:
2037      /* Screen: On; HSync: On, VSync: On */
2038      SEQ01 = 0x00;
2039      DPMSSyncSelect = HSYNC_ON | VSYNC_ON;
2040      break;
2041   case DPMSModeStandby:
2042      /* Screen: Off; HSync: Off, VSync: On */
2043      SEQ01 = 0x20;
2044      DPMSSyncSelect = HSYNC_OFF | VSYNC_ON;
2045      break;
2046   case DPMSModeSuspend:
2047      /* Screen: Off; HSync: On, VSync: Off */
2048      SEQ01 = 0x20;
2049      DPMSSyncSelect = HSYNC_ON | VSYNC_OFF;
2050      break;
2051   case DPMSModeOff:
2052      /* Screen: Off; HSync: Off, VSync: Off */
2053      SEQ01 = 0x20;
2054      DPMSSyncSelect = HSYNC_OFF | VSYNC_OFF;
2055      break;
2056   }
2057
2058   hwp = VGAHWPTR(scrn);
2059
2060   /* Turn the screen on/off */
2061   SEQ01 |= hwp->readSeq(hwp, 0x01) & ~0x20;
2062   hwp->writeSeq(hwp, 0x01, SEQ01);
2063
2064   /* Set the DPMS mode */
2065   OUTREG8(DPMS_SYNC_SELECT, DPMSSyncSelect);
2066}
2067
2068const OptionInfoRec *
2069lg_i810_available_options(int chipid, int busid)
2070{
2071   return I810Options;
2072}
2073
2074
2075Bool lg_i810_init(ScrnInfoPtr scrn)
2076{
2077    scrn->PreInit = I810PreInit;
2078    scrn->ScreenInit = I810ScreenInit;
2079    scrn->SwitchMode = I810SwitchMode;
2080    scrn->AdjustFrame = I810AdjustFrame;
2081    scrn->EnterVT = I810EnterVT;
2082    scrn->LeaveVT = I810LeaveVT;
2083    scrn->FreeScreen = I810FreeScreen;
2084    scrn->ValidMode = I810ValidMode;
2085    return TRUE;
2086}
2087