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