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