r128_driver.c revision a0e1ef58
1c582b7e3Smrg/*
2c582b7e3Smrg * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
3c582b7e3Smrg *                      Precision Insight, Inc., Cedar Park, Texas, and
4c582b7e3Smrg *                      VA Linux Systems Inc., Fremont, California.
5c582b7e3Smrg *
6c582b7e3Smrg * All Rights Reserved.
7c582b7e3Smrg *
8c582b7e3Smrg * Permission is hereby granted, free of charge, to any person obtaining
9c582b7e3Smrg * a copy of this software and associated documentation files (the
10c582b7e3Smrg * "Software"), to deal in the Software without restriction, including
11c582b7e3Smrg * without limitation on the rights to use, copy, modify, merge,
12c582b7e3Smrg * publish, distribute, sublicense, and/or sell copies of the Software,
13c582b7e3Smrg * and to permit persons to whom the Software is furnished to do so,
14c582b7e3Smrg * subject to the following conditions:
15c582b7e3Smrg *
16c582b7e3Smrg * The above copyright notice and this permission notice (including the
17c582b7e3Smrg * next paragraph) shall be included in all copies or substantial
18c582b7e3Smrg * portions of the Software.
19c582b7e3Smrg *
20c582b7e3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21c582b7e3Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22c582b7e3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23c582b7e3Smrg * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, PRECISION INSIGHT, VA LINUX
24c582b7e3Smrg * SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25c582b7e3Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26c582b7e3Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27c582b7e3Smrg * OTHER DEALINGS IN THE SOFTWARE.
28c582b7e3Smrg */
29c582b7e3Smrg
30c582b7e3Smrg#ifdef HAVE_CONFIG_H
31c582b7e3Smrg#include "config.h"
32c582b7e3Smrg#endif
33c582b7e3Smrg
34c582b7e3Smrg/*
35c582b7e3Smrg * Authors:
36c582b7e3Smrg *   Rickard E. Faith <faith@valinux.com>
37c582b7e3Smrg *   Kevin E. Martin <martin@valinux.com>
38c582b7e3Smrg *   Gareth Hughes <gareth@valinux.com>
39c582b7e3Smrg *
40c582b7e3Smrg * Credits:
41c582b7e3Smrg *
42c582b7e3Smrg *   Thanks to Alan Hourihane <alanh@fairlite.demon..co.uk> and SuSE for
43c582b7e3Smrg *   providing source code to their 3.3.x Rage 128 driver.  Portions of
44c582b7e3Smrg *   this file are based on the initialization code for that driver.
45c582b7e3Smrg *
46c582b7e3Smrg * References:
47c582b7e3Smrg *
48c582b7e3Smrg *   RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical
49c582b7e3Smrg *   Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April
50c582b7e3Smrg *   1999.
51c582b7e3Smrg *
52c582b7e3Smrg *   RAGE 128 Software Development Manual (Technical Reference Manual P/N
53c582b7e3Smrg *   SDK-G04000 Rev. 0.01), ATI Technologies: June 1999.
54c582b7e3Smrg *
55c582b7e3Smrg * This server does not yet support these XFree86 4.0 features:
56c582b7e3Smrg *   DDC1 & DDC2
57c582b7e3Smrg *   shadowfb
58c582b7e3Smrg *   overlay planes
59c582b7e3Smrg *
60c582b7e3Smrg * Modified by Marc Aurele La France <tsi@xfree86.org> for ATI driver merge.
61c582b7e3Smrg *
62c582b7e3Smrg * Dualhead support - Alex Deucher <agd5f@yahoo.com>
63c582b7e3Smrg */
64c582b7e3Smrg
65c582b7e3Smrg#include <string.h>
66c582b7e3Smrg#include <stdio.h>
67c582b7e3Smrg
68c582b7e3Smrg				/* Driver data structures */
69c582b7e3Smrg#include "r128.h"
70c582b7e3Smrg#include "r128_probe.h"
71c582b7e3Smrg#include "r128_reg.h"
72c582b7e3Smrg#include "r128_version.h"
73c582b7e3Smrg
7484354367Smrg#ifdef R128DRI
75c582b7e3Smrg#define _XF86DRI_SERVER_
76c582b7e3Smrg#include "r128_dri.h"
77c582b7e3Smrg#include "r128_common.h"
78c582b7e3Smrg#include "r128_sarea.h"
79c582b7e3Smrg#endif
80c582b7e3Smrg
81c582b7e3Smrg				/* colormap initialization */
82c582b7e3Smrg#include "micmap.h"
83c582b7e3Smrg
84c582b7e3Smrg				/* X and server generic header files */
85c582b7e3Smrg#include "xf86.h"
86c582b7e3Smrg#include "xf86_OSproc.h"
87c582b7e3Smrg#include "xf86PciInfo.h"
8819019ffeSmrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
89c582b7e3Smrg#include "xf86RAC.h"
90c582b7e3Smrg#include "xf86Resources.h"
9119019ffeSmrg#endif
92a9060c92Schristos#include "xf86_OSlib.h"
93c582b7e3Smrg#include "xf86cmap.h"
94c582b7e3Smrg#include "xf86xv.h"
95c582b7e3Smrg#include "vbe.h"
9699d7194aSmacallan#include "xf86Priv.h"
97c582b7e3Smrg
98c582b7e3Smrg				/* fbdevhw & vgahw */
99c582b7e3Smrg#ifdef WITH_VGAHW
100c582b7e3Smrg#include "vgaHW.h"
101c582b7e3Smrg#endif
10279e5230eSmacallan
10379e5230eSmacallan#ifndef AVOID_FBDEV
104c582b7e3Smrg#include "fbdevhw.h"
10579e5230eSmacallan#endif
10679e5230eSmacallan
107c582b7e3Smrg#include "dixstruct.h"
108c582b7e3Smrg
109c582b7e3Smrg				/* DPMS support. */
11019019ffeSmrg#ifdef HAVE_XEXTPROTO_71
11119019ffeSmrg#include <X11/extensions/dpmsconst.h>
11219019ffeSmrg#else
113c582b7e3Smrg#define DPMS_SERVER
114c582b7e3Smrg#include <X11/extensions/dpms.h>
11519019ffeSmrg#endif
11619019ffeSmrg
11799d7194aSmacallan#ifdef __NetBSD__
11899d7194aSmacallan#include <sys/time.h>
11999d7194aSmacallan#include <dev/wscons/wsconsio.h>
12099d7194aSmacallan#endif
121c582b7e3Smrg
122c582b7e3Smrg#ifndef MAX
123c582b7e3Smrg#define MAX(a,b) ((a)>(b)?(a):(b))
124c582b7e3Smrg#endif
125c582b7e3Smrg
126c582b7e3Smrg#define USE_CRT_ONLY	0
127c582b7e3Smrg
128c582b7e3Smrg				/* Forward definitions for driver functions */
12984354367Smrgstatic Bool R128CloseScreen(CLOSE_SCREEN_ARGS_DECL);
130c582b7e3Smrgstatic Bool R128SaveScreen(ScreenPtr pScreen, int mode);
131c582b7e3Smrgstatic void R128Save(ScrnInfoPtr pScrn);
132c582b7e3Smrgstatic void R128Restore(ScrnInfoPtr pScrn);
133c582b7e3Smrgstatic Bool R128ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
134c582b7e3Smrgstatic void R128DisplayPowerManagementSet(ScrnInfoPtr pScrn,
135c582b7e3Smrg					  int PowerManagementMode, int flags);
136c582b7e3Smrgstatic void R128DisplayPowerManagementSetLCD(ScrnInfoPtr pScrn,
137c582b7e3Smrg					  int PowerManagementMode, int flags);
138c582b7e3Smrg
139c582b7e3Smrgtypedef enum {
140c582b7e3Smrg  OPTION_NOACCEL,
141c582b7e3Smrg  OPTION_SW_CURSOR,
142c582b7e3Smrg  OPTION_DAC_6BIT,
143c582b7e3Smrg  OPTION_DAC_8BIT,
14484354367Smrg#ifdef R128DRI
145c582b7e3Smrg  OPTION_XV_DMA,
146c582b7e3Smrg  OPTION_IS_PCI,
147c582b7e3Smrg  OPTION_CCE_PIO,
148c582b7e3Smrg  OPTION_NO_SECURITY,
149c582b7e3Smrg  OPTION_USEC_TIMEOUT,
150c582b7e3Smrg  OPTION_AGP_MODE,
151c582b7e3Smrg  OPTION_AGP_SIZE,
152c582b7e3Smrg  OPTION_RING_SIZE,
153c582b7e3Smrg  OPTION_BUFFER_SIZE,
154c582b7e3Smrg  OPTION_PAGE_FLIP,
155c582b7e3Smrg#endif
156c582b7e3Smrg#if USE_CRT_ONLY
157c582b7e3Smrg  /* FIXME: Disable CRTOnly until it is tested */
158c582b7e3Smrg  OPTION_CRT,
159c582b7e3Smrg#endif
160c582b7e3Smrg  OPTION_DISPLAY,
161c582b7e3Smrg  OPTION_PANEL_WIDTH,
162c582b7e3Smrg  OPTION_PANEL_HEIGHT,
163c582b7e3Smrg  OPTION_PROG_FP_REGS,
16479e5230eSmacallan#ifndef AVOID_FBDEV
165c582b7e3Smrg  OPTION_FBDEV,
16679e5230eSmacallan#endif
167c582b7e3Smrg  OPTION_VIDEO_KEY,
168c582b7e3Smrg  OPTION_SHOW_CACHE,
16984354367Smrg  OPTION_VGA_ACCESS,
17084354367Smrg  OPTION_ACCELMETHOD,
17184354367Smrg  OPTION_RENDERACCEL
172c582b7e3Smrg} R128Opts;
173c582b7e3Smrg
174c582b7e3Smrgstatic const OptionInfoRec R128Options[] = {
175c582b7e3Smrg  { OPTION_NOACCEL,      "NoAccel",          OPTV_BOOLEAN, {0}, FALSE },
176c582b7e3Smrg  { OPTION_SW_CURSOR,    "SWcursor",         OPTV_BOOLEAN, {0}, FALSE },
177c582b7e3Smrg  { OPTION_DAC_6BIT,     "Dac6Bit",          OPTV_BOOLEAN, {0}, FALSE },
178c582b7e3Smrg  { OPTION_DAC_8BIT,     "Dac8Bit",          OPTV_BOOLEAN, {0}, TRUE  },
17984354367Smrg#ifdef R128DRI
180c582b7e3Smrg  { OPTION_XV_DMA,       "DMAForXv",         OPTV_BOOLEAN, {0}, FALSE },
181c582b7e3Smrg  { OPTION_IS_PCI,       "ForcePCIMode",     OPTV_BOOLEAN, {0}, FALSE },
182c582b7e3Smrg  { OPTION_CCE_PIO,      "CCEPIOMode",       OPTV_BOOLEAN, {0}, FALSE },
183c582b7e3Smrg  { OPTION_NO_SECURITY,  "CCENoSecurity",    OPTV_BOOLEAN, {0}, FALSE },
184c582b7e3Smrg  { OPTION_USEC_TIMEOUT, "CCEusecTimeout",   OPTV_INTEGER, {0}, FALSE },
185c582b7e3Smrg  { OPTION_AGP_MODE,     "AGPMode",          OPTV_INTEGER, {0}, FALSE },
186c582b7e3Smrg  { OPTION_AGP_SIZE,     "AGPSize",          OPTV_INTEGER, {0}, FALSE },
187c582b7e3Smrg  { OPTION_RING_SIZE,    "RingSize",         OPTV_INTEGER, {0}, FALSE },
188c582b7e3Smrg  { OPTION_BUFFER_SIZE,  "BufferSize",       OPTV_INTEGER, {0}, FALSE },
189c582b7e3Smrg  { OPTION_PAGE_FLIP,    "EnablePageFlip",   OPTV_BOOLEAN, {0}, FALSE },
190c582b7e3Smrg#endif
191c582b7e3Smrg  { OPTION_DISPLAY,      "Display",          OPTV_STRING,  {0}, FALSE },
192c582b7e3Smrg  { OPTION_PANEL_WIDTH,  "PanelWidth",       OPTV_INTEGER, {0}, FALSE },
193c582b7e3Smrg  { OPTION_PANEL_HEIGHT, "PanelHeight",      OPTV_INTEGER, {0}, FALSE },
194c582b7e3Smrg  { OPTION_PROG_FP_REGS, "ProgramFPRegs",    OPTV_BOOLEAN, {0}, FALSE },
19579e5230eSmacallan#ifndef AVOID_FBDEV
196c582b7e3Smrg  { OPTION_FBDEV,        "UseFBDev",         OPTV_BOOLEAN, {0}, FALSE },
19779e5230eSmacallan#endif
198c582b7e3Smrg  { OPTION_VIDEO_KEY,    "VideoKey",         OPTV_INTEGER, {0}, FALSE },
199c582b7e3Smrg  { OPTION_SHOW_CACHE,   "ShowCache",        OPTV_BOOLEAN, {0}, FALSE },
200c582b7e3Smrg  { OPTION_VGA_ACCESS,   "VGAAccess",        OPTV_BOOLEAN, {0}, TRUE  },
20184354367Smrg  { OPTION_ACCELMETHOD,  "AccelMethod",      OPTV_STRING,  {0}, FALSE },
20284354367Smrg  { OPTION_RENDERACCEL,  "RenderAccel",      OPTV_BOOLEAN, {0}, FALSE },
203c582b7e3Smrg  { -1,                  NULL,               OPTV_NONE,    {0}, FALSE }
204c582b7e3Smrg};
205c582b7e3Smrg
206c582b7e3Smrgconst OptionInfoRec *R128OptionsWeak(void) { return R128Options; }
207c582b7e3Smrg
208c582b7e3SmrgR128RAMRec R128RAM[] = {        /* Memory Specifications
209c582b7e3Smrg				   From RAGE 128 Software Development
210c582b7e3Smrg				   Manual (Technical Reference Manual P/N
211c582b7e3Smrg				   SDK-G04000 Rev 0.01), page 3-21.  */
212c582b7e3Smrg    { 4, 4, 3, 3, 1, 3, 1, 16, 12, "128-bit SDR SGRAM 1:1" },
213c582b7e3Smrg    { 4, 8, 3, 3, 1, 3, 1, 17, 13, "64-bit SDR SGRAM 1:1" },
214c582b7e3Smrg    { 4, 4, 1, 2, 1, 2, 1, 16, 12, "64-bit SDR SGRAM 2:1" },
215c582b7e3Smrg    { 4, 4, 3, 3, 2, 3, 1, 16, 12, "64-bit DDR SGRAM" },
216c582b7e3Smrg};
217c582b7e3Smrg
218c582b7e3Smrgextern _X_EXPORT int gR128EntityIndex;
219c582b7e3Smrg
220c582b7e3Smrgint getR128EntityIndex(void)
221c582b7e3Smrg{
222c582b7e3Smrg    return gR128EntityIndex;
223c582b7e3Smrg}
224c582b7e3Smrg
225c582b7e3SmrgR128EntPtr R128EntPriv(ScrnInfoPtr pScrn)
226c582b7e3Smrg{
227c582b7e3Smrg    DevUnion     *pPriv;
228c582b7e3Smrg    R128InfoPtr  info   = R128PTR(pScrn);
229c582b7e3Smrg    pPriv = xf86GetEntityPrivate(info->pEnt->index,
230c582b7e3Smrg                                 getR128EntityIndex());
231c582b7e3Smrg    return pPriv->ptr;
232c582b7e3Smrg}
233c582b7e3Smrg
234c582b7e3Smrg/* Allocate our private R128InfoRec. */
235c582b7e3Smrgstatic Bool R128GetRec(ScrnInfoPtr pScrn)
236c582b7e3Smrg{
237c582b7e3Smrg    if (pScrn->driverPrivate) return TRUE;
238c582b7e3Smrg
239c582b7e3Smrg    pScrn->driverPrivate = xnfcalloc(sizeof(R128InfoRec), 1);
240c582b7e3Smrg    return TRUE;
241c582b7e3Smrg}
242c582b7e3Smrg
243c582b7e3Smrg/* Free our private R128InfoRec. */
244c582b7e3Smrgstatic void R128FreeRec(ScrnInfoPtr pScrn)
245c582b7e3Smrg{
246c582b7e3Smrg    if (!pScrn || !pScrn->driverPrivate) return;
24784354367Smrg    free(pScrn->driverPrivate);
248c582b7e3Smrg    pScrn->driverPrivate = NULL;
249c582b7e3Smrg}
250c582b7e3Smrg
251c582b7e3Smrg/* Memory map the MMIO region.  Used during pre-init and by R128MapMem,
252c582b7e3Smrg   below. */
253c582b7e3Smrgstatic Bool R128MapMMIO(ScrnInfoPtr pScrn)
254c582b7e3Smrg{
255c582b7e3Smrg    R128InfoPtr info          = R128PTR(pScrn);
256c582b7e3Smrg
25779e5230eSmacallan#ifndef AVOID_FBDEV
258c582b7e3Smrg    if (info->FBDev) {
259c582b7e3Smrg	info->MMIO = fbdevHWMapMMIO(pScrn);
26079e5230eSmacallan    } else
26179e5230eSmacallan#endif
26279e5230eSmacallan    {
26319019ffeSmrg        /* If the primary screen has already mapped the MMIO region,
26419019ffeSmrg           use its pointer instead of mapping it a second time. */
26519019ffeSmrg        if (info->IsSecondary) {
26619019ffeSmrg            DevUnion* pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
26719019ffeSmrg                                                   getR128EntityIndex());
26819019ffeSmrg            R128EntPtr pR128Ent = pPriv->ptr;
26919019ffeSmrg            R128InfoPtr info0 = R128PTR(pR128Ent->pPrimaryScrn);
27019019ffeSmrg            info->MMIO=info0->MMIO;
27119019ffeSmrg            if (info->MMIO) return TRUE;
27219019ffeSmrg        }
273c582b7e3Smrg#ifndef XSERVER_LIBPCIACCESS
274c582b7e3Smrg	info->MMIO = xf86MapPciMem(pScrn->scrnIndex,
275c582b7e3Smrg				   VIDMEM_MMIO | VIDMEM_READSIDEEFFECT,
276c582b7e3Smrg				   info->PciTag,
277c582b7e3Smrg				   info->MMIOAddr,
278c582b7e3Smrg				   R128_MMIOSIZE);
279c582b7e3Smrg#else
280c582b7e3Smrg	int err = pci_device_map_range(info->PciInfo,
281c582b7e3Smrg				       info->MMIOAddr,
282c582b7e3Smrg				       R128_MMIOSIZE,
283c582b7e3Smrg				       PCI_DEV_MAP_FLAG_WRITABLE,
284c582b7e3Smrg				       &info->MMIO);
285c582b7e3Smrg
286c582b7e3Smrg	if (err) {
287c582b7e3Smrg	    xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
288c582b7e3Smrg                        "Unable to map MMIO aperture. %s (%d)\n",
289c582b7e3Smrg                        strerror (err), err);
290c582b7e3Smrg	    return FALSE;
291c582b7e3Smrg	}
292c582b7e3Smrg#endif
293c582b7e3Smrg    }
294c582b7e3Smrg
295c582b7e3Smrg    if (!info->MMIO) return FALSE;
296c582b7e3Smrg    return TRUE;
297c582b7e3Smrg}
298c582b7e3Smrg
299c582b7e3Smrg/* Unmap the MMIO region.  Used during pre-init and by R128UnmapMem,
300c582b7e3Smrg   below. */
301c582b7e3Smrgstatic Bool R128UnmapMMIO(ScrnInfoPtr pScrn)
302c582b7e3Smrg{
303c582b7e3Smrg    R128InfoPtr info          = R128PTR(pScrn);
304c582b7e3Smrg
30579e5230eSmacallan#ifndef AVOID_FBDEV
306c582b7e3Smrg    if (info->FBDev)
307c582b7e3Smrg	fbdevHWUnmapMMIO(pScrn);
30879e5230eSmacallan    else
30979e5230eSmacallan#endif
31079e5230eSmacallan    {
311c582b7e3Smrg#ifndef XSERVER_LIBPCIACCESS
312c582b7e3Smrg	xf86UnMapVidMem(pScrn->scrnIndex, info->MMIO, R128_MMIOSIZE);
313c582b7e3Smrg#else
314c582b7e3Smrg	pci_device_unmap_range(info->PciInfo, info->MMIO, R128_MMIOSIZE);
315c582b7e3Smrg#endif
316c582b7e3Smrg    }
317c582b7e3Smrg    info->MMIO = NULL;
318c582b7e3Smrg    return TRUE;
319c582b7e3Smrg}
320c582b7e3Smrg
321c582b7e3Smrg/* Memory map the frame buffer.  Used by R128MapMem, below. */
322c582b7e3Smrgstatic Bool R128MapFB(ScrnInfoPtr pScrn)
323c582b7e3Smrg{
324c582b7e3Smrg    R128InfoPtr info          = R128PTR(pScrn);
325c582b7e3Smrg
32679e5230eSmacallan#ifndef AVOID_FBDEV
327c582b7e3Smrg    if (info->FBDev) {
328c582b7e3Smrg	info->FB = fbdevHWMapVidmem(pScrn);
32979e5230eSmacallan    } else
33079e5230eSmacallan#endif
33179e5230eSmacallan    {
332c582b7e3Smrg#ifndef XSERVER_LIBPCIACCESS
333c582b7e3Smrg	info->FB = xf86MapPciMem(pScrn->scrnIndex,
334c582b7e3Smrg				 VIDMEM_FRAMEBUFFER,
335c582b7e3Smrg				 info->PciTag,
336c582b7e3Smrg				 info->LinearAddr,
337c582b7e3Smrg				 info->FbMapSize);
338c582b7e3Smrg#else
339c582b7e3Smrg	int err = pci_device_map_range(info->PciInfo,
340c582b7e3Smrg				       info->LinearAddr,
341c582b7e3Smrg				       info->FbMapSize,
342c582b7e3Smrg				       PCI_DEV_MAP_FLAG_WRITABLE |
343c582b7e3Smrg				       PCI_DEV_MAP_FLAG_WRITE_COMBINE,
344c582b7e3Smrg				       &info->FB);
345c582b7e3Smrg
346c582b7e3Smrg	if (err) {
347c582b7e3Smrg	    xf86DrvMsg (pScrn->scrnIndex, X_ERROR,
348c582b7e3Smrg                        "Unable to map FB aperture. %s (%d)\n",
349c582b7e3Smrg                        strerror (err), err);
350c582b7e3Smrg	    return FALSE;
351c582b7e3Smrg	}
352c582b7e3Smrg#endif
353c582b7e3Smrg    }
354c582b7e3Smrg
355c582b7e3Smrg    if (!info->FB) return FALSE;
356c582b7e3Smrg    return TRUE;
357c582b7e3Smrg}
358c582b7e3Smrg
359c582b7e3Smrg/* Unmap the frame buffer.  Used by R128UnmapMem, below. */
360c582b7e3Smrgstatic Bool R128UnmapFB(ScrnInfoPtr pScrn)
361c582b7e3Smrg{
362c582b7e3Smrg    R128InfoPtr info          = R128PTR(pScrn);
363c582b7e3Smrg
36479e5230eSmacallan#ifndef AVOID_FBDEV
365c582b7e3Smrg    if (info->FBDev)
366c582b7e3Smrg	fbdevHWUnmapVidmem(pScrn);
367c582b7e3Smrg    else
36879e5230eSmacallan#endif
369c582b7e3Smrg#ifndef XSERVER_LIBPCIACCESS
370c582b7e3Smrg	xf86UnMapVidMem(pScrn->scrnIndex, info->FB, info->FbMapSize);
371c582b7e3Smrg#else
372c582b7e3Smrg	pci_device_unmap_range(info->PciInfo, info->FB, info->FbMapSize);
373c582b7e3Smrg#endif
374c582b7e3Smrg    info->FB = NULL;
375c582b7e3Smrg    return TRUE;
376c582b7e3Smrg}
377c582b7e3Smrg
378c582b7e3Smrg/* Memory map the MMIO region and the frame buffer. */
379c582b7e3Smrgstatic Bool R128MapMem(ScrnInfoPtr pScrn)
380c582b7e3Smrg{
381c582b7e3Smrg    if (!R128MapMMIO(pScrn)) return FALSE;
382c582b7e3Smrg    if (!R128MapFB(pScrn)) {
383c582b7e3Smrg	R128UnmapMMIO(pScrn);
384c582b7e3Smrg	return FALSE;
385c582b7e3Smrg    }
386c582b7e3Smrg    return TRUE;
387c582b7e3Smrg}
388c582b7e3Smrg
389c582b7e3Smrg/* Unmap the MMIO region and the frame buffer. */
390c582b7e3Smrgstatic Bool R128UnmapMem(ScrnInfoPtr pScrn)
391c582b7e3Smrg{
392c582b7e3Smrg    if (!R128UnmapMMIO(pScrn) || !R128UnmapFB(pScrn)) return FALSE;
393c582b7e3Smrg    return TRUE;
394c582b7e3Smrg}
395c582b7e3Smrg
396c582b7e3Smrg/* Read PLL information */
397c582b7e3Smrgunsigned R128INPLL(ScrnInfoPtr pScrn, int addr)
398c582b7e3Smrg{
399c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
400c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
401c582b7e3Smrg
402c582b7e3Smrg    OUTREG8(R128_CLOCK_CNTL_INDEX, addr & 0x3f);
403c582b7e3Smrg    return INREG(R128_CLOCK_CNTL_DATA);
404c582b7e3Smrg}
405c582b7e3Smrg
406c582b7e3Smrg#if 0
407c582b7e3Smrg/* Read PAL information (only used for debugging). */
408c582b7e3Smrgstatic int R128INPAL(int idx)
409c582b7e3Smrg{
410c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
411c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
412c582b7e3Smrg
413c582b7e3Smrg    OUTREG(R128_PALETTE_INDEX, idx << 16);
414c582b7e3Smrg    return INREG(R128_PALETTE_DATA);
415c582b7e3Smrg}
416c582b7e3Smrg#endif
417c582b7e3Smrg
418c582b7e3Smrg/* Wait for vertical sync. */
419c582b7e3Smrgvoid R128WaitForVerticalSync(ScrnInfoPtr pScrn)
420c582b7e3Smrg{
421c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
422c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
423c582b7e3Smrg    int           i;
424c582b7e3Smrg
425c582b7e3Smrg    OUTREG(R128_GEN_INT_STATUS, R128_VSYNC_INT_AK);
426c582b7e3Smrg    for (i = 0; i < R128_TIMEOUT; i++) {
427c582b7e3Smrg	if (INREG(R128_GEN_INT_STATUS) & R128_VSYNC_INT) break;
428c582b7e3Smrg    }
429c582b7e3Smrg}
430c582b7e3Smrg
431c582b7e3Smrg/* Blank screen. */
432c582b7e3Smrgstatic void R128Blank(ScrnInfoPtr pScrn)
433c582b7e3Smrg{
434c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
435c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
436c582b7e3Smrg
437c582b7e3Smrg    if(!info->IsSecondary)
438c582b7e3Smrg    {
439c582b7e3Smrg        switch(info->DisplayType)
440c582b7e3Smrg        {
441c582b7e3Smrg        case MT_LCD:
442c582b7e3Smrg            OUTREGP(R128_LVDS_GEN_CNTL, R128_LVDS_DISPLAY_DIS,
443c582b7e3Smrg                 ~R128_LVDS_DISPLAY_DIS);
444c582b7e3Smrg	    break;
445c582b7e3Smrg        case MT_CRT:
446c582b7e3Smrg            OUTREGP(R128_CRTC_EXT_CNTL, R128_CRTC_DISPLAY_DIS, ~R128_CRTC_DISPLAY_DIS);
447c582b7e3Smrg	    break;
448c582b7e3Smrg        case MT_DFP:
449c582b7e3Smrg            OUTREGP(R128_FP_GEN_CNTL, R128_FP_BLANK_DIS, ~R128_FP_BLANK_DIS);
450c582b7e3Smrg	    break;
451c582b7e3Smrg        case MT_NONE:
452c582b7e3Smrg        default:
453c582b7e3Smrg           break;
454c582b7e3Smrg        }
455c582b7e3Smrg    }
456c582b7e3Smrg    else
457c582b7e3Smrg    {
458c582b7e3Smrg        OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~R128_CRTC2_DISP_DIS);
459c582b7e3Smrg    }
460c582b7e3Smrg}
461c582b7e3Smrg
462c582b7e3Smrg/* Unblank screen. */
463c582b7e3Smrgstatic void R128Unblank(ScrnInfoPtr pScrn)
464c582b7e3Smrg{
465c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
466c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
467c582b7e3Smrg
468c582b7e3Smrg    if(!info->IsSecondary)
469c582b7e3Smrg    {
470c582b7e3Smrg        switch(info->DisplayType)
471c582b7e3Smrg        {
472c582b7e3Smrg        case MT_LCD:
473c582b7e3Smrg            OUTREGP(R128_LVDS_GEN_CNTL, 0,
474c582b7e3Smrg                 ~R128_LVDS_DISPLAY_DIS);
475c582b7e3Smrg	    break;
476c582b7e3Smrg        case MT_CRT:
477c582b7e3Smrg            OUTREGP(R128_CRTC_EXT_CNTL, 0, ~R128_CRTC_DISPLAY_DIS);
478c582b7e3Smrg	    break;
479c582b7e3Smrg        case MT_DFP:
480c582b7e3Smrg            OUTREGP(R128_FP_GEN_CNTL, 0, ~R128_FP_BLANK_DIS);
481c582b7e3Smrg	    break;
482c582b7e3Smrg        case MT_NONE:
483c582b7e3Smrg        default:
484c582b7e3Smrg            break;
485c582b7e3Smrg        }
486c582b7e3Smrg    }
487c582b7e3Smrg    else
488c582b7e3Smrg    {
489c582b7e3Smrg        switch(info->DisplayType)
490c582b7e3Smrg        {
491c582b7e3Smrg        case MT_LCD:
492c582b7e3Smrg        case MT_DFP:
493c582b7e3Smrg        case MT_CRT:
494c582b7e3Smrg            OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_DISP_DIS);
495c582b7e3Smrg            break;
496c582b7e3Smrg        case MT_NONE:
497c582b7e3Smrg        default:
498c582b7e3Smrg            break;
499c582b7e3Smrg        }
500c582b7e3Smrg    }
501c582b7e3Smrg}
502c582b7e3Smrg
503c582b7e3Smrg/* Compute log base 2 of val. */
504c582b7e3Smrgint R128MinBits(int val)
505c582b7e3Smrg{
506c582b7e3Smrg    int bits;
507c582b7e3Smrg
508c582b7e3Smrg    if (!val) return 1;
509c582b7e3Smrg    for (bits = 0; val; val >>= 1, ++bits);
510c582b7e3Smrg    return bits;
511c582b7e3Smrg}
512c582b7e3Smrg
513c582b7e3Smrg/* Compute n/d with rounding. */
514c582b7e3Smrgstatic int R128Div(int n, int d)
515c582b7e3Smrg{
516c582b7e3Smrg    return (n + (d / 2)) / d;
517c582b7e3Smrg}
518c582b7e3Smrg
519c582b7e3Smrg/* Read the Video BIOS block and the FP registers (if applicable). */
520c582b7e3Smrgstatic Bool R128GetBIOSParameters(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
521c582b7e3Smrg{
522c582b7e3Smrg    R128InfoPtr info = R128PTR(pScrn);
523c582b7e3Smrg    int         i;
524c582b7e3Smrg    int         FPHeader = 0;
525c582b7e3Smrg
526c582b7e3Smrg#define R128_BIOS8(v)  (info->VBIOS[v])
527c582b7e3Smrg#define R128_BIOS16(v) (info->VBIOS[v] | \
528c582b7e3Smrg			(info->VBIOS[(v) + 1] << 8))
529c582b7e3Smrg#define R128_BIOS32(v) (info->VBIOS[v] | \
530c582b7e3Smrg			(info->VBIOS[(v) + 1] << 8) | \
531c582b7e3Smrg			(info->VBIOS[(v) + 2] << 16) | \
532c582b7e3Smrg			(info->VBIOS[(v) + 3] << 24))
533c582b7e3Smrg
534c582b7e3Smrg#ifdef XSERVER_LIBPCIACCESS
535c582b7e3Smrg    int size = info->PciInfo->rom_size > R128_VBIOS_SIZE ? info->PciInfo->rom_size : R128_VBIOS_SIZE;
53684354367Smrg    info->VBIOS = malloc(size);
537c582b7e3Smrg#else
53884354367Smrg    info->VBIOS = malloc(R128_VBIOS_SIZE);
539c582b7e3Smrg#endif
540c582b7e3Smrg
541c582b7e3Smrg    if (!info->VBIOS) {
542c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
543c582b7e3Smrg		   "Cannot allocate space for hold Video BIOS!\n");
544c582b7e3Smrg	return FALSE;
545c582b7e3Smrg    }
546c582b7e3Smrg
547c582b7e3Smrg    if (pInt10) {
548c582b7e3Smrg	info->BIOSAddr = pInt10->BIOSseg << 4;
549c582b7e3Smrg	(void)memcpy(info->VBIOS, xf86int10Addr(pInt10, info->BIOSAddr),
550c582b7e3Smrg		     R128_VBIOS_SIZE);
551c582b7e3Smrg    } else {
552c582b7e3Smrg#ifdef XSERVER_LIBPCIACCESS
553c582b7e3Smrg	if (pci_device_read_rom(info->PciInfo, info->VBIOS)) {
554c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
555c582b7e3Smrg		       "Failed to read PCI ROM!\n");
556c582b7e3Smrg	}
557c582b7e3Smrg#else
558c582b7e3Smrg	xf86ReadPciBIOS(0, info->PciTag, 0, info->VBIOS, R128_VBIOS_SIZE);
559c582b7e3Smrg	if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) {
560c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
561c582b7e3Smrg		       "Video BIOS not detected in PCI space!\n");
562c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
563c582b7e3Smrg		       "Attempting to read Video BIOS from legacy ISA space!\n");
564c582b7e3Smrg	    info->BIOSAddr = 0x000c0000;
565c582b7e3Smrg	    xf86ReadDomainMemory(info->PciTag, info->BIOSAddr, R128_VBIOS_SIZE, info->VBIOS);
566c582b7e3Smrg	}
567c582b7e3Smrg#endif
568c582b7e3Smrg    }
569c582b7e3Smrg    if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) {
570c582b7e3Smrg	info->BIOSAddr = 0x00000000;
57184354367Smrg	free(info->VBIOS);
572c582b7e3Smrg	info->VBIOS = NULL;
573c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
574c582b7e3Smrg		   "Video BIOS not found!\n");
575c582b7e3Smrg    }
576c582b7e3Smrg
577c582b7e3Smrg        if(info->HasCRTC2)
578c582b7e3Smrg        {
579c582b7e3Smrg             if(info->IsSecondary)
580c582b7e3Smrg             {
581c582b7e3Smrg		/* there may be a way to detect this, for now, just assume
582c582b7e3Smrg		   second head is CRT */
583c582b7e3Smrg                 info->DisplayType = MT_CRT;
584c582b7e3Smrg
585c582b7e3Smrg                 if(info->DisplayType > MT_NONE)
586c582b7e3Smrg                 {
587c582b7e3Smrg                     DevUnion* pPriv;
588c582b7e3Smrg                     R128EntPtr pR128Ent;
589c582b7e3Smrg                     pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
590c582b7e3Smrg                         getR128EntityIndex());
591c582b7e3Smrg                     pR128Ent = pPriv->ptr;
592c582b7e3Smrg                     pR128Ent->HasSecondary = TRUE;
593c582b7e3Smrg
594c582b7e3Smrg                 }
595c582b7e3Smrg                 else return FALSE;
596c582b7e3Smrg
597c582b7e3Smrg             }
598c582b7e3Smrg             else
599c582b7e3Smrg             {
600c582b7e3Smrg                 /* really need some sort of detection here */
601c582b7e3Smrg		 if (info->HasPanelRegs) {
602c582b7e3Smrg		 	info->DisplayType = MT_LCD;
603c582b7e3Smrg		 } else if (info->isDFP) {
604c582b7e3Smrg			info->DisplayType = MT_DFP;
605c582b7e3Smrg                 } else
606c582b7e3Smrg                 {
607c582b7e3Smrg                     /*DVI port has no monitor connected, try CRT port.
608c582b7e3Smrg                     If something on CRT port, treat it as primary*/
609c582b7e3Smrg                     if(xf86IsEntityShared(pScrn->entityList[0]))
610c582b7e3Smrg                     {
611c582b7e3Smrg                         DevUnion* pPriv;
612c582b7e3Smrg                         R128EntPtr pR128Ent;
613c582b7e3Smrg                         pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
614c582b7e3Smrg                             getR128EntityIndex());
615c582b7e3Smrg                         pR128Ent = pPriv->ptr;
616c582b7e3Smrg                         pR128Ent->BypassSecondary = TRUE;
617c582b7e3Smrg                     }
618c582b7e3Smrg
619c582b7e3Smrg                     info->DisplayType = MT_CRT;
620c582b7e3Smrg#if 0
621c582b7e3Smrg                     {
622c582b7e3Smrg                         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
623c582b7e3Smrg                             "No monitor detected!!!\n");
624c582b7e3Smrg                         return FALSE;
625c582b7e3Smrg                     }
626c582b7e3Smrg#endif
627c582b7e3Smrg                 }
628c582b7e3Smrg             }
629c582b7e3Smrg         }
630c582b7e3Smrg         else
631c582b7e3Smrg         {
632c582b7e3Smrg             /*Regular Radeon ASIC, only one CRTC, but it could be
633c582b7e3Smrg               used for DFP with a DVI output, like AIW board*/
634c582b7e3Smrg             if(info->isDFP) info->DisplayType = MT_DFP;
635c582b7e3Smrg             else info->DisplayType = MT_CRT;
636c582b7e3Smrg         }
637c582b7e3Smrg
638c582b7e3Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s Display == Type %d\n",
639c582b7e3Smrg              (info->IsSecondary ? "Secondary" : "Primary"),
640c582b7e3Smrg               info->DisplayType);
641c582b7e3Smrg
642c582b7e3Smrg
643c582b7e3Smrg    if (info->VBIOS && info->DisplayType == MT_LCD) {
644c582b7e3Smrg	info->FPBIOSstart = 0;
645c582b7e3Smrg
646c582b7e3Smrg	/* FIXME: There should be direct access to the start of the FP info
647c582b7e3Smrg	   tables, but until we find out where that offset is stored, we
648c582b7e3Smrg	   must search for the ATI signature string: "M3      ". */
649c582b7e3Smrg	for (i = 4; i < R128_VBIOS_SIZE-8; i++) {
650c582b7e3Smrg	    if (R128_BIOS8(i)   == 'M' &&
651c582b7e3Smrg		R128_BIOS8(i+1) == '3' &&
652c582b7e3Smrg		R128_BIOS8(i+2) == ' ' &&
653c582b7e3Smrg		R128_BIOS8(i+3) == ' ' &&
654c582b7e3Smrg		R128_BIOS8(i+4) == ' ' &&
655c582b7e3Smrg		R128_BIOS8(i+5) == ' ' &&
656c582b7e3Smrg		R128_BIOS8(i+6) == ' ' &&
657c582b7e3Smrg		R128_BIOS8(i+7) == ' ') {
658c582b7e3Smrg		FPHeader = i-2;
659c582b7e3Smrg		break;
660c582b7e3Smrg	    }
661c582b7e3Smrg	}
662c582b7e3Smrg
663c582b7e3Smrg	if (!FPHeader) return TRUE;
664c582b7e3Smrg
665c582b7e3Smrg	/* Assume that only one panel is attached and supported */
666c582b7e3Smrg	for (i = FPHeader+20; i < FPHeader+84; i += 2) {
667c582b7e3Smrg	    if (R128_BIOS16(i) != 0) {
668c582b7e3Smrg		info->FPBIOSstart = R128_BIOS16(i);
669c582b7e3Smrg		break;
670c582b7e3Smrg	    }
671c582b7e3Smrg	}
672c582b7e3Smrg	if (!info->FPBIOSstart) return TRUE;
673c582b7e3Smrg
674c582b7e3Smrg	if (!info->PanelXRes)
675c582b7e3Smrg	    info->PanelXRes = R128_BIOS16(info->FPBIOSstart+25);
676c582b7e3Smrg	if (!info->PanelYRes)
677c582b7e3Smrg	    info->PanelYRes = R128_BIOS16(info->FPBIOSstart+27);
678c582b7e3Smrg
679c582b7e3Smrg	info->PanelPwrDly = R128_BIOS8(info->FPBIOSstart+56);
680c582b7e3Smrg
681c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel ID: ");
682c582b7e3Smrg	for (i = 1; i <= 24; i++)
683c582b7e3Smrg	    ErrorF("%c", R128_BIOS8(info->FPBIOSstart+i));
684c582b7e3Smrg	ErrorF("\n");
685c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel Type: ");
686c582b7e3Smrg	i = R128_BIOS16(info->FPBIOSstart+29);
687c582b7e3Smrg	if (i & 1) ErrorF("Color, ");
688c582b7e3Smrg	else       ErrorF("Monochrome, ");
689c582b7e3Smrg	if (i & 2) ErrorF("Dual(split), ");
690c582b7e3Smrg	else       ErrorF("Single, ");
691c582b7e3Smrg	switch ((i >> 2) & 0x3f) {
692c582b7e3Smrg	case 0:  ErrorF("STN");        break;
693c582b7e3Smrg	case 1:  ErrorF("TFT");        break;
694c582b7e3Smrg	case 2:  ErrorF("Active STN"); break;
695c582b7e3Smrg	case 3:  ErrorF("EL");         break;
696c582b7e3Smrg	case 4:  ErrorF("Plasma");     break;
697c582b7e3Smrg	default: ErrorF("UNKNOWN");    break;
698c582b7e3Smrg	}
699c582b7e3Smrg	ErrorF("\n");
700c582b7e3Smrg	if (R128_BIOS8(info->FPBIOSstart+61) & 1) {
701c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel Interface: LVDS\n");
702c582b7e3Smrg	} else {
703c582b7e3Smrg	    /* FIXME: Add Non-LVDS flat pael support */
704c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
705c582b7e3Smrg		       "Non-LVDS panel interface detected!  "
706c582b7e3Smrg		       "This support is untested and may not "
707c582b7e3Smrg		       "function properly\n");
708c582b7e3Smrg	}
709c582b7e3Smrg    }
710c582b7e3Smrg
71199d7194aSmacallan#ifdef __NetBSD__
71299d7194aSmacallan    if (!info->PanelXRes || !info->PanelYRes) {
71399d7194aSmacallan	/*
71499d7194aSmacallan	 * we may not be on x86 so check wsdisplay for panel dimensions
71599d7194aSmacallan	 * XXX this assumes that the r128 is the console, although that should
71699d7194aSmacallan	 * be the case in the vast majority of cases where an LCD is hooked up
71799d7194aSmacallan	 * directly
71899d7194aSmacallan	 * We should probably just check the relevant registers but I'm not
71999d7194aSmacallan	 * sure they're available at this point.
72099d7194aSmacallan	 */
72199d7194aSmacallan	struct wsdisplay_fbinfo fbinfo;
72299d7194aSmacallan
72399d7194aSmacallan	if (ioctl(xf86Info.screenFd, WSDISPLAYIO_GINFO, &fbinfo) == 0) {
72499d7194aSmacallan	    info->PanelXRes = fbinfo.width;
72599d7194aSmacallan	    info->PanelYRes = fbinfo.height;
72699d7194aSmacallan	}
72799d7194aSmacallan    }
72899d7194aSmacallan#endif
72999d7194aSmacallan
730c582b7e3Smrg    if (!info->PanelXRes || !info->PanelYRes) {
731c582b7e3Smrg        info->HasPanelRegs = FALSE;
732c582b7e3Smrg        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
733c582b7e3Smrg		   "Can't determine panel dimensions, and none specified.\n"
734c582b7e3Smrg		   "\tDisabling programming of FP registers.\n");
73599d7194aSmacallan    } else {
73699d7194aSmacallan	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel size: %dx%d\n",
73799d7194aSmacallan		   info->PanelXRes, info->PanelYRes);
738c582b7e3Smrg    }
739c582b7e3Smrg
740c582b7e3Smrg    return TRUE;
741c582b7e3Smrg}
742c582b7e3Smrg
743c582b7e3Smrg/* Read PLL parameters from BIOS block.  Default to typical values if there
744c582b7e3Smrg   is no BIOS. */
745c582b7e3Smrgstatic Bool R128GetPLLParameters(ScrnInfoPtr pScrn)
746c582b7e3Smrg{
747c582b7e3Smrg    R128InfoPtr   info = R128PTR(pScrn);
748c582b7e3Smrg    R128PLLPtr    pll  = &info->pll;
749c582b7e3Smrg
750c582b7e3Smrg#if defined(__powerpc__) || defined(__alpha__)
751c582b7e3Smrg    /* there is no bios under Linux PowerPC but Open Firmware
752c582b7e3Smrg       does set up the PLL registers properly and we can use
753c582b7e3Smrg       those to calculate xclk and find the reference divider */
754c582b7e3Smrg
755c582b7e3Smrg    unsigned x_mpll_ref_fb_div;
756c582b7e3Smrg    unsigned xclk_cntl;
757c582b7e3Smrg    unsigned Nx, M;
758c582b7e3Smrg    unsigned PostDivSet[] = {0, 1, 2, 4, 8, 3, 6, 12};
759c582b7e3Smrg
760c582b7e3Smrg    /* Assume REF clock is 2950 (in units of 10khz) */
761c582b7e3Smrg    /* and that all pllclk must be between 125 Mhz and 250Mhz */
762c582b7e3Smrg    pll->reference_freq = 2950;
763c582b7e3Smrg    pll->min_pll_freq   = 12500;
764c582b7e3Smrg    pll->max_pll_freq   = 25000;
765c582b7e3Smrg
766c582b7e3Smrg    /* need to memory map the io to use INPLL since it
767c582b7e3Smrg       has not been done yet at this point in the startup */
768c582b7e3Smrg    R128MapMMIO(pScrn);
769c582b7e3Smrg    x_mpll_ref_fb_div = INPLL(pScrn, R128_X_MPLL_REF_FB_DIV);
770c582b7e3Smrg    xclk_cntl = INPLL(pScrn, R128_XCLK_CNTL) & 0x7;
771c582b7e3Smrg    pll->reference_div =
772c582b7e3Smrg	INPLL(pScrn,R128_PPLL_REF_DIV) & R128_PPLL_REF_DIV_MASK;
773c582b7e3Smrg    /* unmap it again */
774c582b7e3Smrg    R128UnmapMMIO(pScrn);
775c582b7e3Smrg
776c582b7e3Smrg    Nx = (x_mpll_ref_fb_div & 0x00FF00) >> 8;
777c582b7e3Smrg    M =  (x_mpll_ref_fb_div & 0x0000FF);
778c582b7e3Smrg
779c582b7e3Smrg    pll->xclk =  R128Div((2 * Nx * pll->reference_freq),
780c582b7e3Smrg			 (M * PostDivSet[xclk_cntl]));
781c582b7e3Smrg
782c582b7e3Smrg#else /* !defined(__powerpc__) */
783c582b7e3Smrg
784c582b7e3Smrg    if (!info->VBIOS) {
785c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
786c582b7e3Smrg		   "Video BIOS not detected, using default PLL parameters!\n");
787c582b7e3Smrg				/* These probably aren't going to work for
788c582b7e3Smrg				   the card you are using.  Specifically,
789c582b7e3Smrg				   reference freq can be 29.50MHz,
790c582b7e3Smrg				   28.63MHz, or 14.32MHz.  YMMV. */
791c582b7e3Smrg	pll->reference_freq = 2950;
792c582b7e3Smrg	pll->reference_div  = 65;
793c582b7e3Smrg	pll->min_pll_freq   = 12500;
794c582b7e3Smrg	pll->max_pll_freq   = 25000;
795c582b7e3Smrg	pll->xclk           = 10300;
796c582b7e3Smrg    } else {
797c582b7e3Smrg	CARD16 bios_header    = R128_BIOS16(0x48);
798c582b7e3Smrg	CARD16 pll_info_block = R128_BIOS16(bios_header + 0x30);
799c582b7e3Smrg	R128TRACE(("Header at 0x%04x; PLL Information at 0x%04x\n",
800c582b7e3Smrg		   bios_header, pll_info_block));
801c582b7e3Smrg
802c582b7e3Smrg	pll->reference_freq = R128_BIOS16(pll_info_block + 0x0e);
803c582b7e3Smrg	pll->reference_div  = R128_BIOS16(pll_info_block + 0x10);
804c582b7e3Smrg	pll->min_pll_freq   = R128_BIOS32(pll_info_block + 0x12);
805c582b7e3Smrg	pll->max_pll_freq   = R128_BIOS32(pll_info_block + 0x16);
806c582b7e3Smrg	pll->xclk           = R128_BIOS16(pll_info_block + 0x08);
807c582b7e3Smrg    }
808c582b7e3Smrg#endif /* __powerpc__ */
809c582b7e3Smrg
810c582b7e3Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
811c582b7e3Smrg	       "PLL parameters: rf=%d rd=%d min=%d max=%d; xclk=%d\n",
812c582b7e3Smrg	       pll->reference_freq,
813c582b7e3Smrg	       pll->reference_div,
814c582b7e3Smrg	       pll->min_pll_freq,
815c582b7e3Smrg	       pll->max_pll_freq,
816c582b7e3Smrg	       pll->xclk);
817c582b7e3Smrg
818c582b7e3Smrg    return TRUE;
819c582b7e3Smrg}
820c582b7e3Smrg
821c582b7e3Smrg/* This is called by R128PreInit to set up the default visual. */
822c582b7e3Smrgstatic Bool R128PreInitVisual(ScrnInfoPtr pScrn)
823c582b7e3Smrg{
824c582b7e3Smrg    R128InfoPtr info          = R128PTR(pScrn);
825c582b7e3Smrg
826c582b7e3Smrg    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, (Support24bppFb
827c582b7e3Smrg					  | Support32bppFb
828c582b7e3Smrg					  | SupportConvert32to24
829c582b7e3Smrg					  )))
830c582b7e3Smrg	return FALSE;
831c582b7e3Smrg
832c582b7e3Smrg    switch (pScrn->depth) {
833c582b7e3Smrg    case 8:
834c582b7e3Smrg    case 15:
835c582b7e3Smrg    case 16:
836c582b7e3Smrg    case 24:
837c582b7e3Smrg	break;
838c582b7e3Smrg    default:
839c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
840c582b7e3Smrg		   "Given depth (%d) is not supported by %s driver\n",
841c582b7e3Smrg		   pScrn->depth, R128_DRIVER_NAME);
842c582b7e3Smrg	return FALSE;
843c582b7e3Smrg    }
844c582b7e3Smrg
845c582b7e3Smrg    xf86PrintDepthBpp(pScrn);
846c582b7e3Smrg
847c582b7e3Smrg    info->fifo_slots  = 0;
848c582b7e3Smrg    info->pix24bpp    = xf86GetBppFromDepth(pScrn, pScrn->depth);
849c582b7e3Smrg    info->CurrentLayout.bitsPerPixel = pScrn->bitsPerPixel;
850c582b7e3Smrg    info->CurrentLayout.depth        = pScrn->depth;
851c582b7e3Smrg    info->CurrentLayout.pixel_bytes  = pScrn->bitsPerPixel / 8;
852c582b7e3Smrg    info->CurrentLayout.pixel_code   = (pScrn->bitsPerPixel != 16
853c582b7e3Smrg				       ? pScrn->bitsPerPixel
854c582b7e3Smrg				       : pScrn->depth);
855c582b7e3Smrg
856c582b7e3Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
857c582b7e3Smrg	       "Pixel depth = %d bits stored in %d byte%s (%d bpp pixmaps)\n",
858c582b7e3Smrg	       pScrn->depth,
859c582b7e3Smrg	       info->CurrentLayout.pixel_bytes,
860c582b7e3Smrg	       info->CurrentLayout.pixel_bytes > 1 ? "s" : "",
861c582b7e3Smrg	       info->pix24bpp);
862c582b7e3Smrg
863c582b7e3Smrg
864c582b7e3Smrg    if (!xf86SetDefaultVisual(pScrn, -1)) return FALSE;
865c582b7e3Smrg
866c582b7e3Smrg    if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
867c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
868c582b7e3Smrg		   "Default visual (%s) is not supported at depth %d\n",
869c582b7e3Smrg		   xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
870c582b7e3Smrg	return FALSE;
871c582b7e3Smrg    }
872c582b7e3Smrg    return TRUE;
873c582b7e3Smrg
874c582b7e3Smrg}
875c582b7e3Smrg
876c582b7e3Smrg/* This is called by R128PreInit to handle all color weight issues. */
877c582b7e3Smrgstatic Bool R128PreInitWeight(ScrnInfoPtr pScrn)
878c582b7e3Smrg{
879c582b7e3Smrg    R128InfoPtr info          = R128PTR(pScrn);
880c582b7e3Smrg
881c582b7e3Smrg				/* Save flag for 6 bit DAC to use for
882c582b7e3Smrg				   setting CRTC registers.  Otherwise use
883c582b7e3Smrg				   an 8 bit DAC, even if xf86SetWeight sets
884c582b7e3Smrg				   pScrn->rgbBits to some value other than
885c582b7e3Smrg				   8. */
886c582b7e3Smrg    info->dac6bits = FALSE;
887c582b7e3Smrg    if (pScrn->depth > 8) {
888c582b7e3Smrg	rgb defaultWeight = { 0, 0, 0 };
889c582b7e3Smrg	if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) return FALSE;
890c582b7e3Smrg    } else {
891c582b7e3Smrg	pScrn->rgbBits = 8;
892c582b7e3Smrg	if (xf86ReturnOptValBool(info->Options, OPTION_DAC_6BIT, FALSE)) {
893c582b7e3Smrg	    pScrn->rgbBits = 6;
894c582b7e3Smrg	    info->dac6bits = TRUE;
895c582b7e3Smrg	}
896c582b7e3Smrg    }
897c582b7e3Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
898c582b7e3Smrg	       "Using %d bits per RGB (%d bit DAC)\n",
899c582b7e3Smrg	       pScrn->rgbBits, info->dac6bits ? 6 : 8);
900c582b7e3Smrg
901c582b7e3Smrg    return TRUE;
902c582b7e3Smrg
903c582b7e3Smrg}
904c582b7e3Smrg
905c582b7e3Smrg/* This is called by R128PreInit to handle config file overrides for things
906c582b7e3Smrg   like chipset and memory regions.  Also determine memory size and type.
907c582b7e3Smrg   If memory type ever needs an override, put it in this routine. */
908c582b7e3Smrgstatic Bool R128PreInitConfig(ScrnInfoPtr pScrn)
909c582b7e3Smrg{
910c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
911c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
912c582b7e3Smrg    EntityInfoPtr pEnt      = info->pEnt;
913c582b7e3Smrg    GDevPtr       dev       = pEnt->device;
914c582b7e3Smrg    int           offset    = 0;        /* RAM Type */
915c582b7e3Smrg    MessageType   from;
916c582b7e3Smrg
917c582b7e3Smrg				/* Chipset */
918c582b7e3Smrg    from = X_PROBED;
919c582b7e3Smrg    if (dev->chipset && *dev->chipset) {
920c582b7e3Smrg	info->Chipset  = xf86StringToToken(R128Chipsets, dev->chipset);
921c582b7e3Smrg	from           = X_CONFIG;
922c582b7e3Smrg    } else if (dev->chipID >= 0) {
923c582b7e3Smrg	info->Chipset  = dev->chipID;
924c582b7e3Smrg	from           = X_CONFIG;
925c582b7e3Smrg    } else {
926c582b7e3Smrg	info->Chipset = PCI_DEV_DEVICE_ID(info->PciInfo);
927c582b7e3Smrg    }
928c582b7e3Smrg    pScrn->chipset = (char *)xf86TokenToString(R128Chipsets, info->Chipset);
929c582b7e3Smrg
930c582b7e3Smrg    if (!pScrn->chipset) {
931c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
932c582b7e3Smrg		   "ChipID 0x%04x is not recognized\n", info->Chipset);
933c582b7e3Smrg	return FALSE;
934c582b7e3Smrg    }
935c582b7e3Smrg
936c582b7e3Smrg    if (info->Chipset < 0) {
937c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
938c582b7e3Smrg		   "Chipset \"%s\" is not recognized\n", pScrn->chipset);
939c582b7e3Smrg	return FALSE;
940c582b7e3Smrg    }
941c582b7e3Smrg
942c582b7e3Smrg    xf86DrvMsg(pScrn->scrnIndex, from,
943c582b7e3Smrg	       "Chipset: \"%s\" (ChipID = 0x%04x)\n",
944c582b7e3Smrg	       pScrn->chipset,
945c582b7e3Smrg	       info->Chipset);
946c582b7e3Smrg
947c582b7e3Smrg				/* Framebuffer */
948c582b7e3Smrg
949c582b7e3Smrg    from             = X_PROBED;
950c582b7e3Smrg    info->LinearAddr = PCI_REGION_BASE(info->PciInfo, 0, REGION_MEM) & 0xfc000000;
951c582b7e3Smrg    pScrn->memPhysBase = info->LinearAddr;
952c582b7e3Smrg    if (dev->MemBase) {
953c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
954c582b7e3Smrg		   "Linear address override, using 0x%08lx instead of 0x%08lx\n",
955c582b7e3Smrg		   dev->MemBase,
956c582b7e3Smrg		   info->LinearAddr);
957c582b7e3Smrg	info->LinearAddr = dev->MemBase;
958c582b7e3Smrg	from             = X_CONFIG;
959c582b7e3Smrg    } else if (!info->LinearAddr) {
960c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
961c582b7e3Smrg		   "No valid linear framebuffer address\n");
962c582b7e3Smrg	return FALSE;
963c582b7e3Smrg    }
964c582b7e3Smrg    xf86DrvMsg(pScrn->scrnIndex, from,
965c582b7e3Smrg	       "Linear framebuffer at 0x%08lx\n", info->LinearAddr);
966c582b7e3Smrg
967c582b7e3Smrg				/* MMIO registers */
968c582b7e3Smrg    from             = X_PROBED;
969c582b7e3Smrg    info->MMIOAddr   = PCI_REGION_BASE(info->PciInfo, 2, REGION_MEM) & 0xffffff00;
970c582b7e3Smrg    if (dev->IOBase) {
971c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
972c582b7e3Smrg		   "MMIO address override, using 0x%08lx instead of 0x%08lx\n",
973c582b7e3Smrg		   dev->IOBase,
974c582b7e3Smrg		   info->MMIOAddr);
975c582b7e3Smrg	info->MMIOAddr = dev->IOBase;
976c582b7e3Smrg	from           = X_CONFIG;
977c582b7e3Smrg    } else if (!info->MMIOAddr) {
978c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid MMIO address\n");
979c582b7e3Smrg	return FALSE;
980c582b7e3Smrg    }
981c582b7e3Smrg    xf86DrvMsg(pScrn->scrnIndex, from,
982c582b7e3Smrg	       "MMIO registers at 0x%08lx\n", info->MMIOAddr);
983c582b7e3Smrg
984c582b7e3Smrg#ifndef XSERVER_LIBPCIACCESS
985c582b7e3Smrg				/* BIOS */
986c582b7e3Smrg    from              = X_PROBED;
987c582b7e3Smrg    info->BIOSAddr    = info->PciInfo->biosBase & 0xfffe0000;
988c582b7e3Smrg    if (info->BIOSAddr) {
989c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, from,
990c582b7e3Smrg		   "BIOS at 0x%08lx\n", info->BIOSAddr);
991c582b7e3Smrg    }
992c582b7e3Smrg#endif
993c582b7e3Smrg
994c582b7e3Smrg				/* Flat panel (part 1) */
995c582b7e3Smrg    if (xf86GetOptValBool(info->Options, OPTION_PROG_FP_REGS,
996c582b7e3Smrg			  &info->HasPanelRegs)) {
997c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
998c582b7e3Smrg		   "Turned flat panel register programming %s\n",
999c582b7e3Smrg		   info->HasPanelRegs ? "on" : "off");
1000c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1001c582b7e3Smrg		   "\n\nWARNING: Forcing the driver to use/not use the flat panel registers\nmight damage your flat panel.  Use at your *OWN* *RISK*.\n\n");
1002c582b7e3Smrg    } else {
1003c582b7e3Smrg        info->isDFP = FALSE;
1004c582b7e3Smrg        info->isPro2 = FALSE;
1005c582b7e3Smrg        info->HasCRTC2 = FALSE;
1006c582b7e3Smrg	switch (info->Chipset) {
1007c582b7e3Smrg	/* R128 Pro and Pro2 can have DFP, we will deal with it.
1008c582b7e3Smrg	   No support for dual-head/xinerama yet.
1009c582b7e3Smrg           M3 can also have DFP, no support for now */
1010c582b7e3Smrg	case PCI_CHIP_RAGE128TF:
1011c582b7e3Smrg	case PCI_CHIP_RAGE128TL:
1012c582b7e3Smrg	case PCI_CHIP_RAGE128TR:
1013c582b7e3Smrg	/* FIXME: RAGE128 TS/TT/TU are assumed to be PRO2 as all 6 chips came
1014c582b7e3Smrg	 *        out at the same time, so are of the same family likely.
1015c582b7e3Smrg	 *        This requires confirmation however to be fully correct.
1016c582b7e3Smrg	 *        Mike A. Harris <mharris@redhat.com>
1017c582b7e3Smrg	 */
1018c582b7e3Smrg	case PCI_CHIP_RAGE128TS:
1019c582b7e3Smrg	case PCI_CHIP_RAGE128TT:
1020c582b7e3Smrg	case PCI_CHIP_RAGE128TU: info->isPro2 = TRUE;
1021c582b7e3Smrg	/* FIXME: RAGE128 P[ABCEGHIJKLMNOQSTUVWX] are assumed to have DFP
1022c582b7e3Smrg	 *        capability, as the comment at the top suggests.
1023c582b7e3Smrg	 *        This requires confirmation however to be fully correct.
1024c582b7e3Smrg	 *        Mike A. Harris <mharris@redhat.com>
1025c582b7e3Smrg	 */
1026c582b7e3Smrg	case PCI_CHIP_RAGE128PA:
1027c582b7e3Smrg	case PCI_CHIP_RAGE128PB:
1028c582b7e3Smrg	case PCI_CHIP_RAGE128PC:
1029c582b7e3Smrg	case PCI_CHIP_RAGE128PE:
1030c582b7e3Smrg	case PCI_CHIP_RAGE128PG:
1031c582b7e3Smrg	case PCI_CHIP_RAGE128PH:
1032c582b7e3Smrg	case PCI_CHIP_RAGE128PI:
1033c582b7e3Smrg	case PCI_CHIP_RAGE128PJ:
1034c582b7e3Smrg	case PCI_CHIP_RAGE128PK:
1035c582b7e3Smrg	case PCI_CHIP_RAGE128PL:
1036c582b7e3Smrg	case PCI_CHIP_RAGE128PM:
1037c582b7e3Smrg	case PCI_CHIP_RAGE128PN:
1038c582b7e3Smrg	case PCI_CHIP_RAGE128PO:
1039c582b7e3Smrg	case PCI_CHIP_RAGE128PQ:
1040c582b7e3Smrg	case PCI_CHIP_RAGE128PS:
1041c582b7e3Smrg	case PCI_CHIP_RAGE128PT:
1042c582b7e3Smrg	case PCI_CHIP_RAGE128PU:
1043c582b7e3Smrg	case PCI_CHIP_RAGE128PV:
1044c582b7e3Smrg	case PCI_CHIP_RAGE128PW:
1045c582b7e3Smrg	case PCI_CHIP_RAGE128PX:
1046c582b7e3Smrg
1047c582b7e3Smrg	case PCI_CHIP_RAGE128PD:
1048c582b7e3Smrg	case PCI_CHIP_RAGE128PF:
1049c582b7e3Smrg	case PCI_CHIP_RAGE128PP:
1050c582b7e3Smrg	case PCI_CHIP_RAGE128PR: info->isDFP = TRUE; break;
1051c582b7e3Smrg
1052c582b7e3Smrg	case PCI_CHIP_RAGE128LE:
1053c582b7e3Smrg	case PCI_CHIP_RAGE128LF:
1054c582b7e3Smrg	case PCI_CHIP_RAGE128MF:
1055c582b7e3Smrg	case PCI_CHIP_RAGE128ML:
1056d6cc4c59Smacallan			info->HasPanelRegs = TRUE;
1057d6cc4c59Smacallan			info->isDFP = TRUE;
1058c582b7e3Smrg			/* which chips support dualhead? */
1059c582b7e3Smrg			info->HasCRTC2 = TRUE;
1060c582b7e3Smrg			break;
1061c582b7e3Smrg	case PCI_CHIP_RAGE128RE:
1062c582b7e3Smrg	case PCI_CHIP_RAGE128RF:
1063c582b7e3Smrg	case PCI_CHIP_RAGE128RG:
1064c582b7e3Smrg	case PCI_CHIP_RAGE128RK:
1065c582b7e3Smrg	case PCI_CHIP_RAGE128RL:
1066c582b7e3Smrg	case PCI_CHIP_RAGE128SM:
1067c582b7e3Smrg	/* FIXME: RAGE128 S[EFGHKLN] are assumed to be like the SM above as
1068c582b7e3Smrg	 *        all of them are listed as "Rage 128 4x" in ATI docs.
1069c582b7e3Smrg	 *        This requires confirmation however to be fully correct.
1070c582b7e3Smrg	 *        Mike A. Harris <mharris@redhat.com>
1071c582b7e3Smrg	 */
1072c582b7e3Smrg	case PCI_CHIP_RAGE128SE:
1073c582b7e3Smrg	case PCI_CHIP_RAGE128SF:
1074c582b7e3Smrg	case PCI_CHIP_RAGE128SG:
1075c582b7e3Smrg	case PCI_CHIP_RAGE128SH:
1076c582b7e3Smrg	case PCI_CHIP_RAGE128SK:
1077c582b7e3Smrg	case PCI_CHIP_RAGE128SL:
1078c582b7e3Smrg	case PCI_CHIP_RAGE128SN:
1079c582b7e3Smrg	default:                 info->HasPanelRegs = FALSE; break;
1080c582b7e3Smrg	}
1081c582b7e3Smrg    }
1082c582b7e3Smrg
1083c582b7e3Smrg				/* Read registers used to determine options */
1084c582b7e3Smrg    from                      = X_PROBED;
1085c582b7e3Smrg    R128MapMMIO(pScrn);
1086c582b7e3Smrg    R128MMIO                  = info->MMIO;
1087c582b7e3Smrg
108879e5230eSmacallan#ifndef AVOID_FBDEV
1089c582b7e3Smrg    if (info->FBDev)
1090c582b7e3Smrg	pScrn->videoRam       = fbdevHWGetVidmem(pScrn) / 1024;
1091c582b7e3Smrg    else
109279e5230eSmacallan#endif
1093c582b7e3Smrg	pScrn->videoRam       = INREG(R128_CONFIG_MEMSIZE) / 1024;
1094c582b7e3Smrg
1095c582b7e3Smrg    info->MemCntl             = INREG(R128_MEM_CNTL);
1096c582b7e3Smrg    info->BusCntl             = INREG(R128_BUS_CNTL);
1097c582b7e3Smrg
1098c582b7e3Smrg    /* On non-flat panel systems, the default is to display to the CRT,
1099c582b7e3Smrg       and on flat panel systems, the default is to display to the flat
1100c582b7e3Smrg       panel unless the user explicity chooses otherwise using the "Display"
1101c582b7e3Smrg       config file setting.  BIOS_5_SCRATCH holds the display device on flat
1102c582b7e3Smrg       panel systems only. */
1103c582b7e3Smrg    if (info->HasPanelRegs) {
1104c582b7e3Smrg        char *Display = xf86GetOptValString(info->Options, OPTION_DISPLAY);
1105c582b7e3Smrg
110679e5230eSmacallan#ifndef AVOID_FBDEV
1107c582b7e3Smrg	if (info->FBDev)
1108c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1109c582b7e3Smrg		     "Option \"Display\" ignored "
1110c582b7e3Smrg		     "(framebuffer device determines display type)\n");
111179e5230eSmacallan	else
111279e5230eSmacallan#endif
111379e5230eSmacallan	 if (info->IsPrimary || info->IsSecondary)
1114c582b7e3Smrg	    info->BIOSDisplay = R128_DUALHEAD;
1115c582b7e3Smrg	else if (!Display || !xf86NameCmp(Display, "FP"))
1116c582b7e3Smrg	    info->BIOSDisplay = R128_BIOS_DISPLAY_FP;
1117c582b7e3Smrg	else if (!xf86NameCmp(Display, "BIOS"))
1118c582b7e3Smrg	    info->BIOSDisplay = INREG8(R128_BIOS_5_SCRATCH);
1119c582b7e3Smrg	else if (!xf86NameCmp(Display, "Mirror"))
1120c582b7e3Smrg	    info->BIOSDisplay = R128_BIOS_DISPLAY_FP_CRT;
1121c582b7e3Smrg	else if (!xf86NameCmp(Display, "CRT"))
1122c582b7e3Smrg	    info->BIOSDisplay = R128_BIOS_DISPLAY_CRT;
1123c582b7e3Smrg	else {
1124c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1125c582b7e3Smrg		"Unsupported type \"%s\" specified for Option \"Display\".\n"
1126c582b7e3Smrg		"\tSupported types are: "
1127c582b7e3Smrg		"\"BIOS\", \"Mirror\", \"CRT\" and \"FP\"\n", Display);
1128c582b7e3Smrg	    return FALSE;
1129c582b7e3Smrg	}
1130c582b7e3Smrg    } else {
1131c582b7e3Smrg	info->BIOSDisplay     = R128_BIOS_DISPLAY_CRT;
1132c582b7e3Smrg    }
1133c582b7e3Smrg
1134c582b7e3Smrg    R128MMIO                  = NULL;
1135c582b7e3Smrg    R128UnmapMMIO(pScrn);
1136c582b7e3Smrg
1137c582b7e3Smrg				/* RAM */
1138c582b7e3Smrg    switch (info->MemCntl & 0x3) {
1139c582b7e3Smrg    case 0:                     /* SDR SGRAM 1:1 */
1140c582b7e3Smrg	switch (info->Chipset) {
1141c582b7e3Smrg	case PCI_CHIP_RAGE128TF:
1142c582b7e3Smrg	case PCI_CHIP_RAGE128TL:
1143c582b7e3Smrg	case PCI_CHIP_RAGE128TR:
1144c582b7e3Smrg	case PCI_CHIP_RAGE128LE:
1145c582b7e3Smrg	case PCI_CHIP_RAGE128LF:
1146c582b7e3Smrg	case PCI_CHIP_RAGE128MF:
1147c582b7e3Smrg	case PCI_CHIP_RAGE128ML:
1148c582b7e3Smrg	case PCI_CHIP_RAGE128RE:
1149c582b7e3Smrg	case PCI_CHIP_RAGE128RF:
1150c582b7e3Smrg	case PCI_CHIP_RAGE128RG: offset = 0; break; /* 128-bit SDR SGRAM 1:1 */
1151c582b7e3Smrg	case PCI_CHIP_RAGE128RK:
1152c582b7e3Smrg	case PCI_CHIP_RAGE128RL:
1153c582b7e3Smrg	case PCI_CHIP_RAGE128SM:
1154c582b7e3Smrg	default:                 offset = 1; break; /*  64-bit SDR SGRAM 1:1 */
1155c582b7e3Smrg	}
1156c582b7e3Smrg	break;
1157c582b7e3Smrg    case 1:                      offset = 2; break; /*  64-bit SDR SGRAM 2:1 */
1158c582b7e3Smrg    case 2:                      offset = 3; break; /*  64-bit DDR SGRAM     */
1159c582b7e3Smrg    default:                     offset = 1; break; /*  64-bit SDR SGRAM 1:1 */
1160c582b7e3Smrg    }
1161c582b7e3Smrg    info->ram = &R128RAM[offset];
1162c582b7e3Smrg
1163c582b7e3Smrg    if (dev->videoRam) {
1164c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1165c582b7e3Smrg		   "Video RAM override, using %d kB instead of %d kB\n",
1166c582b7e3Smrg		   dev->videoRam,
1167c582b7e3Smrg		   pScrn->videoRam);
1168c582b7e3Smrg	from             = X_CONFIG;
1169c582b7e3Smrg	pScrn->videoRam  = dev->videoRam;
1170c582b7e3Smrg    }
1171c582b7e3Smrg
1172c582b7e3Smrg    xf86DrvMsg(pScrn->scrnIndex, from,
1173c582b7e3Smrg	       "VideoRAM: %d kByte (%s)\n", pScrn->videoRam, info->ram->name);
1174c582b7e3Smrg
1175c582b7e3Smrg    if (info->IsPrimary) {
1176c582b7e3Smrg        pScrn->videoRam /= 2;
1177c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1178c582b7e3Smrg		"Using %dk of videoram for primary head\n",
1179c582b7e3Smrg		pScrn->videoRam);
1180c582b7e3Smrg    }
1181c582b7e3Smrg
1182c582b7e3Smrg    if (info->IsSecondary) {
1183c582b7e3Smrg        pScrn->videoRam /= 2;
1184c582b7e3Smrg        info->LinearAddr += pScrn->videoRam * 1024;
1185c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1186c582b7e3Smrg		"Using %dk of videoram for secondary head\n",
1187c582b7e3Smrg		pScrn->videoRam);
1188c582b7e3Smrg    }
1189c582b7e3Smrg
1190c582b7e3Smrg    pScrn->videoRam  &= ~1023;
1191c582b7e3Smrg    info->FbMapSize  = pScrn->videoRam * 1024;
1192c582b7e3Smrg
1193c582b7e3Smrg
1194c582b7e3Smrg				/* Flat panel (part 2) */
1195c582b7e3Smrg	switch (info->BIOSDisplay) {
1196c582b7e3Smrg	case R128_DUALHEAD:
1197c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1198c582b7e3Smrg		       "Dual display\n");
1199c582b7e3Smrg	    break;
1200c582b7e3Smrg	case R128_BIOS_DISPLAY_FP:
1201c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1202c582b7e3Smrg		       "Using flat panel for display\n");
1203c582b7e3Smrg	    break;
1204c582b7e3Smrg	case R128_BIOS_DISPLAY_CRT:
1205c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1206c582b7e3Smrg		       "Using external CRT for display\n");
1207c582b7e3Smrg	    break;
1208c582b7e3Smrg	case R128_BIOS_DISPLAY_FP_CRT:
1209c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1210c582b7e3Smrg		       "Using both flat panel and external CRT "
1211c582b7e3Smrg		       "for display\n");
1212c582b7e3Smrg	    break;
1213c582b7e3Smrg	}
1214c582b7e3Smrg
1215c582b7e3Smrg    if (info->HasPanelRegs) {
1216c582b7e3Smrg				/* Panel width/height overrides */
1217c582b7e3Smrg	info->PanelXRes = 0;
1218c582b7e3Smrg	info->PanelYRes = 0;
1219c582b7e3Smrg	if (xf86GetOptValInteger(info->Options,
1220c582b7e3Smrg				 OPTION_PANEL_WIDTH, &(info->PanelXRes))) {
1221c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1222c582b7e3Smrg		       "Flat panel width: %d\n", info->PanelXRes);
1223c582b7e3Smrg	}
1224c582b7e3Smrg	if (xf86GetOptValInteger(info->Options,
1225c582b7e3Smrg				 OPTION_PANEL_HEIGHT, &(info->PanelYRes))) {
1226c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1227c582b7e3Smrg		       "Flat panel height: %d\n", info->PanelYRes);
1228c582b7e3Smrg	}
1229c582b7e3Smrg    }
1230c582b7e3Smrg
123184354367Smrg#ifdef R128DRI
1232c582b7e3Smrg				/* DMA for Xv */
1233c582b7e3Smrg    info->DMAForXv = xf86ReturnOptValBool(info->Options, OPTION_XV_DMA, FALSE);
1234c582b7e3Smrg    if (info->DMAForXv) {
1235c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1236c582b7e3Smrg		   "Will try to use DMA for Xv image transfers\n");
1237c582b7e3Smrg    }
1238c582b7e3Smrg
1239c582b7e3Smrg				/* AGP/PCI */
1240c582b7e3Smrg    if (xf86ReturnOptValBool(info->Options, OPTION_IS_PCI, FALSE)) {
1241c582b7e3Smrg	info->IsPCI = TRUE;
1242c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forced into PCI-only mode\n");
1243c582b7e3Smrg    } else {
1244c582b7e3Smrg	switch (info->Chipset) {
1245c582b7e3Smrg	case PCI_CHIP_RAGE128LE:
1246c582b7e3Smrg	case PCI_CHIP_RAGE128RE:
1247c582b7e3Smrg	case PCI_CHIP_RAGE128RK:
1248c582b7e3Smrg	case PCI_CHIP_RAGE128PD:
1249c582b7e3Smrg	case PCI_CHIP_RAGE128PR:
1250c582b7e3Smrg	case PCI_CHIP_RAGE128PP: info->IsPCI = TRUE;  break;
1251c582b7e3Smrg	case PCI_CHIP_RAGE128LF:
1252c582b7e3Smrg	case PCI_CHIP_RAGE128MF:
1253c582b7e3Smrg	case PCI_CHIP_RAGE128ML:
1254c582b7e3Smrg	case PCI_CHIP_RAGE128PF:
1255c582b7e3Smrg	case PCI_CHIP_RAGE128RF:
1256c582b7e3Smrg	case PCI_CHIP_RAGE128RG:
1257c582b7e3Smrg	case PCI_CHIP_RAGE128RL:
1258c582b7e3Smrg	case PCI_CHIP_RAGE128SM:
1259c582b7e3Smrg	case PCI_CHIP_RAGE128TF:
1260c582b7e3Smrg	case PCI_CHIP_RAGE128TL:
1261c582b7e3Smrg	case PCI_CHIP_RAGE128TR:
1262c582b7e3Smrg	/* FIXME: Rage 128 S[EFGHKLN], T[STU], P[ABCEGHIJKLMNOQSTUVWX] are
1263c582b7e3Smrg	 * believed to be AGP, but need confirmation. <mharris@redhat.com>
1264c582b7e3Smrg	 */
1265c582b7e3Smrg	case PCI_CHIP_RAGE128PA:
1266c582b7e3Smrg	case PCI_CHIP_RAGE128PB:
1267c582b7e3Smrg	case PCI_CHIP_RAGE128PC:
1268c582b7e3Smrg	case PCI_CHIP_RAGE128PE:
1269c582b7e3Smrg	case PCI_CHIP_RAGE128PG:
1270c582b7e3Smrg	case PCI_CHIP_RAGE128PH:
1271c582b7e3Smrg	case PCI_CHIP_RAGE128PI:
1272c582b7e3Smrg	case PCI_CHIP_RAGE128PJ:
1273c582b7e3Smrg	case PCI_CHIP_RAGE128PK:
1274c582b7e3Smrg	case PCI_CHIP_RAGE128PL:
1275c582b7e3Smrg	case PCI_CHIP_RAGE128PM:
1276c582b7e3Smrg	case PCI_CHIP_RAGE128PN:
1277c582b7e3Smrg	case PCI_CHIP_RAGE128PO:
1278c582b7e3Smrg	case PCI_CHIP_RAGE128PQ:
1279c582b7e3Smrg	case PCI_CHIP_RAGE128PS:
1280c582b7e3Smrg	case PCI_CHIP_RAGE128PT:
1281c582b7e3Smrg	case PCI_CHIP_RAGE128PU:
1282c582b7e3Smrg	case PCI_CHIP_RAGE128PV:
1283c582b7e3Smrg	case PCI_CHIP_RAGE128PW:
1284c582b7e3Smrg	case PCI_CHIP_RAGE128PX:
1285c582b7e3Smrg	case PCI_CHIP_RAGE128TS:
1286c582b7e3Smrg	case PCI_CHIP_RAGE128TT:
1287c582b7e3Smrg	case PCI_CHIP_RAGE128TU:
1288c582b7e3Smrg	case PCI_CHIP_RAGE128SE:
1289c582b7e3Smrg	case PCI_CHIP_RAGE128SF:
1290c582b7e3Smrg	case PCI_CHIP_RAGE128SG:
1291c582b7e3Smrg	case PCI_CHIP_RAGE128SH:
1292c582b7e3Smrg	case PCI_CHIP_RAGE128SK:
1293c582b7e3Smrg	case PCI_CHIP_RAGE128SL:
1294c582b7e3Smrg	case PCI_CHIP_RAGE128SN:
1295c582b7e3Smrg	default:                 info->IsPCI = FALSE; break;
1296c582b7e3Smrg	}
1297c582b7e3Smrg    }
1298c582b7e3Smrg#endif
1299c582b7e3Smrg
1300c582b7e3Smrg    return TRUE;
1301c582b7e3Smrg}
1302c582b7e3Smrg
1303c582b7e3Smrgstatic Bool R128PreInitDDC(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
1304c582b7e3Smrg{
1305c582b7e3Smrg#if !defined(__powerpc__) && !defined(__alpha__) && !defined(__sparc__)
1306c582b7e3Smrg    R128InfoPtr   info = R128PTR(pScrn);
1307c582b7e3Smrg    vbeInfoPtr pVbe;
1308c582b7e3Smrg#endif
1309c582b7e3Smrg
1310c582b7e3Smrg    if (!xf86LoadSubModule(pScrn, "ddc")) return FALSE;
1311c582b7e3Smrg
1312c582b7e3Smrg#if defined(__powerpc__) || defined(__alpha__) || defined(__sparc__)
1313c582b7e3Smrg    /* Int10 is broken on PPC and some Alphas */
1314c582b7e3Smrg    return TRUE;
1315c582b7e3Smrg#else
1316c582b7e3Smrg    if (xf86LoadSubModule(pScrn, "vbe")) {
1317c582b7e3Smrg	pVbe = VBEInit(pInt10,info->pEnt->index);
1318c582b7e3Smrg	if (!pVbe) return FALSE;
1319c582b7e3Smrg        xf86SetDDCproperties(pScrn,xf86PrintEDID(vbeDoEDID(pVbe,NULL)));
1320c582b7e3Smrg	vbeFree(pVbe);
1321c582b7e3Smrg	return TRUE;
1322c582b7e3Smrg    } else
1323c582b7e3Smrg	return FALSE;
1324c582b7e3Smrg#endif
1325c582b7e3Smrg}
1326c582b7e3Smrg
1327c582b7e3Smrg/* This is called by R128PreInit to initialize gamma correction. */
1328c582b7e3Smrgstatic Bool R128PreInitGamma(ScrnInfoPtr pScrn)
1329c582b7e3Smrg{
1330c582b7e3Smrg    Gamma zeros = { 0.0, 0.0, 0.0 };
1331c582b7e3Smrg
1332c582b7e3Smrg    if (!xf86SetGamma(pScrn, zeros)) return FALSE;
1333c582b7e3Smrg    return TRUE;
1334c582b7e3Smrg}
1335c582b7e3Smrg
1336c582b7e3Smrgstatic void
1337c582b7e3SmrgR128I2CGetBits(I2CBusPtr b, int *Clock, int *data)
1338c582b7e3Smrg{
1339c582b7e3Smrg    ScrnInfoPtr   pScrn       = xf86Screens[b->scrnIndex];
1340c582b7e3Smrg    R128InfoPtr info = R128PTR(pScrn);
1341c582b7e3Smrg    unsigned long val;
1342c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
1343c582b7e3Smrg
1344c582b7e3Smrg    /* Get the result. */
1345c582b7e3Smrg    val = INREG(info->DDCReg);
1346c582b7e3Smrg    *Clock = (val & R128_GPIO_MONID_Y_3) != 0;
1347c582b7e3Smrg    *data  = (val & R128_GPIO_MONID_Y_0) != 0;
1348c582b7e3Smrg
1349c582b7e3Smrg}
1350c582b7e3Smrg
1351c582b7e3Smrgstatic void
1352c582b7e3SmrgR128I2CPutBits(I2CBusPtr b, int Clock, int data)
1353c582b7e3Smrg{
1354c582b7e3Smrg    ScrnInfoPtr   pScrn       = xf86Screens[b->scrnIndex];
1355c582b7e3Smrg    R128InfoPtr info = R128PTR(pScrn);
1356c582b7e3Smrg    unsigned long val;
1357c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
1358c582b7e3Smrg
1359c582b7e3Smrg    val = INREG(info->DDCReg)
1360c582b7e3Smrg              & ~(CARD32)(R128_GPIO_MONID_EN_0 | R128_GPIO_MONID_EN_3);
1361c582b7e3Smrg    val |= (Clock ? 0:R128_GPIO_MONID_EN_3);
1362c582b7e3Smrg    val |= (data ? 0:R128_GPIO_MONID_EN_0);
1363c582b7e3Smrg    OUTREG(info->DDCReg, val);
1364c582b7e3Smrg}
1365c582b7e3Smrg
1366c582b7e3Smrg
1367c582b7e3Smrgstatic Bool
1368c582b7e3SmrgR128I2cInit(ScrnInfoPtr pScrn)
1369c582b7e3Smrg{
1370c582b7e3Smrg    R128InfoPtr info = R128PTR(pScrn);
1371c582b7e3Smrg    if ( !xf86LoadSubModule(pScrn, "i2c") ) {
1372c582b7e3Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1373c582b7e3Smrg            "Failed to load i2c module\n");
1374c582b7e3Smrg		return FALSE;
1375c582b7e3Smrg    }
1376c582b7e3Smrg
1377c582b7e3Smrg    info->pI2CBus = xf86CreateI2CBusRec();
1378c582b7e3Smrg    if(!info->pI2CBus) return FALSE;
1379c582b7e3Smrg
1380c582b7e3Smrg    info->pI2CBus->BusName    = "DDC";
1381c582b7e3Smrg    info->pI2CBus->scrnIndex  = pScrn->scrnIndex;
1382c582b7e3Smrg    info->DDCReg = R128_GPIO_MONID;
1383c582b7e3Smrg    info->pI2CBus->I2CPutBits = R128I2CPutBits;
1384c582b7e3Smrg    info->pI2CBus->I2CGetBits = R128I2CGetBits;
1385c582b7e3Smrg    info->pI2CBus->AcknTimeout = 5;
1386c582b7e3Smrg
1387c582b7e3Smrg    if (!xf86I2CBusInit(info->pI2CBus)) {
1388c582b7e3Smrg        return FALSE;
1389c582b7e3Smrg    }
1390c582b7e3Smrg    return TRUE;
1391c582b7e3Smrg}
1392c582b7e3Smrg
1393e86a9069Smacallan/* XXX
1394e86a9069Smacallan * the following comment is bogus - the code scans the main monitor port,
1395e86a9069Smacallan * not R128_GPIO_MONIDB
1396e86a9069Smacallan */
1397c582b7e3Smrg/* return TRUE is a DFP is indeed connected to a DVI port */
1398c582b7e3Smrgstatic Bool R128GetDFPInfo(ScrnInfoPtr pScrn)
1399c582b7e3Smrg{
1400c582b7e3Smrg    R128InfoPtr info  = R128PTR(pScrn);
1401c582b7e3Smrg    int i;
1402c582b7e3Smrg    xf86MonPtr MonInfo = NULL;
1403c582b7e3Smrg    xf86MonPtr ddc;
1404c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
1405c582b7e3Smrg
1406c582b7e3Smrg    if(!R128I2cInit(pScrn)){
1407c582b7e3Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1408c582b7e3Smrg                  "I2C initialization failed!\n");
1409c582b7e3Smrg    }
1410c582b7e3Smrg
1411c582b7e3Smrg    OUTREG(info->DDCReg, (INREG(info->DDCReg)
1412c582b7e3Smrg           | R128_GPIO_MONID_MASK_0 | R128_GPIO_MONID_MASK_3));
1413c582b7e3Smrg
1414c582b7e3Smrg    OUTREG(info->DDCReg, INREG(info->DDCReg)
1415c582b7e3Smrg           & ~(CARD32)(R128_GPIO_MONID_A_0 | R128_GPIO_MONID_A_3));
1416c582b7e3Smrg
141784354367Smrg    MonInfo = xf86DoEDID_DDC2(XF86_SCRN_ARG(pScrn), info->pI2CBus);
1418e86a9069Smacallan#ifdef __NetBSD__
1419d6cc4c59Smacallan    if (MonInfo == NULL) {
1420e86a9069Smacallan    	struct wsdisplayio_edid_info ei;
1421e86a9069Smacallan    	char buffer[1024];
1422e86a9069Smacallan    	int i, j;
1423e86a9069Smacallan
1424e86a9069Smacallan	ei.edid_data = buffer;
1425e86a9069Smacallan	ei.buffer_size = 1024;
1426e86a9069Smacallan	if (ioctl(xf86Info.screenFd, WSDISPLAYIO_GET_EDID, &ei) != -1) {
1427e86a9069Smacallan	    xf86Msg(X_INFO, "got %d bytes worth of EDID from wsdisplay\n", ei.data_size);
1428e86a9069Smacallan	    MonInfo = xf86InterpretEDID(pScrn->scrnIndex, buffer);
1429e86a9069Smacallan	} else
1430e86a9069Smacallan	    xf86Msg(X_INFO, "ioctl failed %d\n", errno);
1431e86a9069Smacallan    }
1432e86a9069Smacallan#endif
1433e86a9069Smacallan
1434c582b7e3Smrg    if(!MonInfo) {
1435c582b7e3Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1436c582b7e3Smrg                   "No DFP detected\n");
1437c582b7e3Smrg        return FALSE;
1438c582b7e3Smrg    }
1439c582b7e3Smrg    xf86SetDDCproperties(pScrn, MonInfo);
1440c582b7e3Smrg    ddc = pScrn->monitor->DDC;
1441c582b7e3Smrg
1442c582b7e3Smrg    for(i=0; i<4; i++)
1443c582b7e3Smrg    {
1444c582b7e3Smrg        if((ddc->det_mon[i].type == 0) &&
1445c582b7e3Smrg	  (ddc->det_mon[i].section.d_timings.h_active > 0) &&
1446c582b7e3Smrg	  (ddc->det_mon[i].section.d_timings.v_active > 0))
1447c582b7e3Smrg        {
1448c582b7e3Smrg            info->PanelXRes =
1449c582b7e3Smrg                ddc->det_mon[i].section.d_timings.h_active;
1450c582b7e3Smrg            info->PanelYRes =
1451c582b7e3Smrg                ddc->det_mon[i].section.d_timings.v_active;
1452c582b7e3Smrg
1453c582b7e3Smrg            info->HOverPlus =
1454c582b7e3Smrg                ddc->det_mon[i].section.d_timings.h_sync_off;
1455c582b7e3Smrg            info->HSyncWidth =
1456c582b7e3Smrg                ddc->det_mon[i].section.d_timings.h_sync_width;
1457c582b7e3Smrg            info->HBlank =
1458c582b7e3Smrg                ddc->det_mon[i].section.d_timings.h_blanking;
1459c582b7e3Smrg            info->VOverPlus =
1460c582b7e3Smrg                ddc->det_mon[i].section.d_timings.v_sync_off;
1461c582b7e3Smrg            info->VSyncWidth =
1462c582b7e3Smrg                ddc->det_mon[i].section.d_timings.v_sync_width;
1463c582b7e3Smrg            info->VBlank =
1464c582b7e3Smrg                ddc->det_mon[i].section.d_timings.v_blanking;
1465c582b7e3Smrg        }
1466c582b7e3Smrg    }
1467c582b7e3Smrg    return TRUE;
1468c582b7e3Smrg}
1469c582b7e3Smrg
1470c582b7e3Smrg
1471c582b7e3Smrgstatic void R128SetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag)
1472c582b7e3Smrg{
1473c582b7e3Smrg    int i;
1474c582b7e3Smrg    xf86MonPtr ddc = pScrn->monitor->DDC;
1475c582b7e3Smrg    if(flag)  /*HSync*/
1476c582b7e3Smrg    {
1477c582b7e3Smrg        for(i=0; i<4; i++)
1478c582b7e3Smrg        {
1479c582b7e3Smrg            if(ddc->det_mon[i].type == DS_RANGES)
1480c582b7e3Smrg            {
1481c582b7e3Smrg                pScrn->monitor->nHsync = 1;
1482c582b7e3Smrg                pScrn->monitor->hsync[0].lo =
1483c582b7e3Smrg                    ddc->det_mon[i].section.ranges.min_h;
1484c582b7e3Smrg                pScrn->monitor->hsync[0].hi =
1485c582b7e3Smrg                    ddc->det_mon[i].section.ranges.max_h;
1486c582b7e3Smrg                return;
1487c582b7e3Smrg            }
1488c582b7e3Smrg        }
1489c582b7e3Smrg        /*if no sync ranges detected in detailed timing table,
1490c582b7e3Smrg          let's try to derive them from supported VESA modes
1491c582b7e3Smrg          Are we doing too much here!!!?
1492c582b7e3Smrg        **/
1493c582b7e3Smrg        i = 0;
1494c582b7e3Smrg        if(ddc->timings1.t1 & 0x02) /*800x600@56*/
1495c582b7e3Smrg        {
1496c582b7e3Smrg            pScrn->monitor->hsync[i].lo =
1497c582b7e3Smrg                pScrn->monitor->hsync[i].hi = 35.2;
1498c582b7e3Smrg            i++;
1499c582b7e3Smrg        }
1500c582b7e3Smrg        if(ddc->timings1.t1 & 0x04) /*640x480@75*/
1501c582b7e3Smrg        {
1502c582b7e3Smrg            pScrn->monitor->hsync[i].lo =
1503c582b7e3Smrg                pScrn->monitor->hsync[i].hi = 37.5;
1504c582b7e3Smrg            i++;
1505c582b7e3Smrg        }
1506c582b7e3Smrg        if((ddc->timings1.t1 & 0x08) || (ddc->timings1.t1 & 0x01))
1507c582b7e3Smrg        {
1508c582b7e3Smrg            pScrn->monitor->hsync[i].lo =
1509c582b7e3Smrg                pScrn->monitor->hsync[i].hi = 37.9;
1510c582b7e3Smrg            i++;
1511c582b7e3Smrg        }
1512c582b7e3Smrg        if(ddc->timings1.t2 & 0x40)
1513c582b7e3Smrg        {
1514c582b7e3Smrg            pScrn->monitor->hsync[i].lo =
1515c582b7e3Smrg                pScrn->monitor->hsync[i].hi = 46.9;
1516c582b7e3Smrg            i++;
1517c582b7e3Smrg        }
1518c582b7e3Smrg        if((ddc->timings1.t2 & 0x80) || (ddc->timings1.t2 & 0x08))
1519c582b7e3Smrg        {
1520c582b7e3Smrg            pScrn->monitor->hsync[i].lo =
1521c582b7e3Smrg                pScrn->monitor->hsync[i].hi = 48.1;
1522c582b7e3Smrg            i++;
1523c582b7e3Smrg        }
1524c582b7e3Smrg        if(ddc->timings1.t2 & 0x04)
1525c582b7e3Smrg        {
1526c582b7e3Smrg            pScrn->monitor->hsync[i].lo =
1527c582b7e3Smrg                pScrn->monitor->hsync[i].hi = 56.5;
1528c582b7e3Smrg            i++;
1529c582b7e3Smrg        }
1530c582b7e3Smrg        if(ddc->timings1.t2 & 0x02)
1531c582b7e3Smrg        {
1532c582b7e3Smrg            pScrn->monitor->hsync[i].lo =
1533c582b7e3Smrg                pScrn->monitor->hsync[i].hi = 60.0;
1534c582b7e3Smrg            i++;
1535c582b7e3Smrg        }
1536c582b7e3Smrg        if(ddc->timings1.t2 & 0x01)
1537c582b7e3Smrg        {
1538c582b7e3Smrg            pScrn->monitor->hsync[i].lo =
1539c582b7e3Smrg                pScrn->monitor->hsync[i].hi = 64.0;
1540c582b7e3Smrg            i++;
1541c582b7e3Smrg        }
1542c582b7e3Smrg        pScrn->monitor->nHsync = i;
1543c582b7e3Smrg    }
1544c582b7e3Smrg    else      /*Vrefresh*/
1545c582b7e3Smrg    {
1546c582b7e3Smrg        for(i=0; i<4; i++)
1547c582b7e3Smrg        {
1548c582b7e3Smrg            if(ddc->det_mon[i].type == DS_RANGES)
1549c582b7e3Smrg            {
1550c582b7e3Smrg                pScrn->monitor->nVrefresh = 1;
1551c582b7e3Smrg                pScrn->monitor->vrefresh[0].lo =
1552c582b7e3Smrg                    ddc->det_mon[i].section.ranges.min_v;
1553c582b7e3Smrg                pScrn->monitor->vrefresh[0].hi =
1554c582b7e3Smrg                    ddc->det_mon[i].section.ranges.max_v;
1555c582b7e3Smrg                return;
1556c582b7e3Smrg            }
1557c582b7e3Smrg        }
1558c582b7e3Smrg        i = 0;
1559c582b7e3Smrg        if(ddc->timings1.t1 & 0x02) /*800x600@56*/
1560c582b7e3Smrg        {
1561c582b7e3Smrg            pScrn->monitor->vrefresh[i].lo =
1562c582b7e3Smrg                pScrn->monitor->vrefresh[i].hi = 56;
1563c582b7e3Smrg            i++;
1564c582b7e3Smrg        }
1565c582b7e3Smrg        if((ddc->timings1.t1 & 0x01) || (ddc->timings1.t2 & 0x08))
1566c582b7e3Smrg        {
1567c582b7e3Smrg            pScrn->monitor->vrefresh[i].lo =
1568c582b7e3Smrg                pScrn->monitor->vrefresh[i].hi = 60;
1569c582b7e3Smrg            i++;
1570c582b7e3Smrg        }
1571c582b7e3Smrg        if(ddc->timings1.t2 & 0x04)
1572c582b7e3Smrg        {
1573c582b7e3Smrg            pScrn->monitor->vrefresh[i].lo =
1574c582b7e3Smrg                pScrn->monitor->vrefresh[i].hi = 70;
1575c582b7e3Smrg            i++;
1576c582b7e3Smrg        }
1577c582b7e3Smrg        if((ddc->timings1.t1 & 0x08) || (ddc->timings1.t2 & 0x80))
1578c582b7e3Smrg        {
1579c582b7e3Smrg            pScrn->monitor->vrefresh[i].lo =
1580c582b7e3Smrg                pScrn->monitor->vrefresh[i].hi = 72;
1581c582b7e3Smrg            i++;
1582c582b7e3Smrg        }
1583c582b7e3Smrg        if((ddc->timings1.t1 & 0x04) || (ddc->timings1.t2 & 0x40)
1584c582b7e3Smrg           || (ddc->timings1.t2 & 0x02) || (ddc->timings1.t2 & 0x01))
1585c582b7e3Smrg        {
1586c582b7e3Smrg            pScrn->monitor->vrefresh[i].lo =
1587c582b7e3Smrg                pScrn->monitor->vrefresh[i].hi = 75;
1588c582b7e3Smrg            i++;
1589c582b7e3Smrg        }
1590c582b7e3Smrg        pScrn->monitor->nVrefresh = i;
1591c582b7e3Smrg    }
1592c582b7e3Smrg}
1593c582b7e3Smrg
1594c582b7e3Smrg/***********
159584354367Smrg   free's xf86ValidateModes routine deosn't work well with DFPs
1596c582b7e3Smrg   here is our own validation routine. All modes between
1597c582b7e3Smrg   640<=XRes<=MaxRes and 480<=YRes<=MaxYRes will be permitted.
1598c582b7e3Smrg   NOTE: RageProII doesn't support rmx, can only work with the
1599c582b7e3Smrg         standard modes the monitor can support (scale).
1600c582b7e3Smrg************/
1601c582b7e3Smrg
1602c582b7e3Smrgstatic int R128ValidateFPModes(ScrnInfoPtr pScrn)
1603c582b7e3Smrg{
1604c582b7e3Smrg    int i, j, count=0, width, height;
1605c582b7e3Smrg    R128InfoPtr info = R128PTR(pScrn);
1606c582b7e3Smrg    DisplayModePtr last = NULL, new = NULL, first = NULL;
1607c582b7e3Smrg    xf86MonPtr ddc;
1608c582b7e3Smrg
1609c582b7e3Smrg    /* Free any allocated modes during configuration. We don't need them*/
1610c582b7e3Smrg    while (pScrn->modes)
1611c582b7e3Smrg    {
1612c582b7e3Smrg	    xf86DeleteMode(&pScrn->modes, pScrn->modes);
1613c582b7e3Smrg    }
1614c582b7e3Smrg    while (pScrn->modePool)
1615c582b7e3Smrg    {
1616c582b7e3Smrg	    xf86DeleteMode(&pScrn->modePool, pScrn->modePool);
1617c582b7e3Smrg    }
1618c582b7e3Smrg
1619c582b7e3Smrg    pScrn->virtualX = pScrn->display->virtualX;
1620c582b7e3Smrg    pScrn->virtualY = pScrn->display->virtualY;
1621c582b7e3Smrg
1622c582b7e3Smrg    /* If no mode specified in config, we use native resolution*/
1623c582b7e3Smrg    if(!pScrn->display->modes[0])
1624c582b7e3Smrg    {
1625c582b7e3Smrg        pScrn->display->modes[0] = xnfalloc(16);
1626c582b7e3Smrg        sprintf(pScrn->display->modes[0], "%dx%d",
1627c582b7e3Smrg               info->PanelXRes, info->PanelYRes);
1628c582b7e3Smrg    }
1629c582b7e3Smrg
1630c582b7e3Smrg    for(i=0; pScrn->display->modes[i] != NULL; i++)
1631c582b7e3Smrg    {
1632c582b7e3Smrg        if (sscanf(pScrn->display->modes[i], "%dx%d", &width, &height) == 2)
1633c582b7e3Smrg        {
1634c582b7e3Smrg
1635c582b7e3Smrg            if(width < 640 || width > info->PanelXRes ||
1636c582b7e3Smrg               height < 480 || height > info->PanelYRes)
1637c582b7e3Smrg            {
1638c582b7e3Smrg                xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1639c582b7e3Smrg                    "Mode %s is out of range.\n"
1640c582b7e3Smrg                    "Valid mode should be between 640x480-%dx%d\n",
1641c582b7e3Smrg                    pScrn->display->modes[i], info->PanelXRes, info->PanelYRes);
1642c582b7e3Smrg                continue;
1643c582b7e3Smrg            }
1644c582b7e3Smrg
1645c582b7e3Smrg            new = xnfcalloc(1, sizeof(DisplayModeRec));
1646c582b7e3Smrg            new->prev = last;
1647c582b7e3Smrg            new->name = xnfalloc(strlen(pScrn->display->modes[i]) + 1);
1648c582b7e3Smrg            strcpy(new->name, pScrn->display->modes[i]);
1649c582b7e3Smrg            new->HDisplay = new->CrtcHDisplay = width;
1650c582b7e3Smrg            new->VDisplay = new->CrtcVDisplay = height;
1651c582b7e3Smrg
1652c582b7e3Smrg            ddc = pScrn->monitor->DDC;
1653c582b7e3Smrg            for(j=0; j<DET_TIMINGS; j++)
1654c582b7e3Smrg            {
1655c582b7e3Smrg                /*We use native mode clock only*/
1656c582b7e3Smrg                if(ddc->det_mon[j].type == 0){
1657c582b7e3Smrg                    new->Clock = ddc->det_mon[j].section.d_timings.clock / 1000;
1658c582b7e3Smrg                    break;
1659c582b7e3Smrg                }
1660c582b7e3Smrg            }
1661c582b7e3Smrg
1662c582b7e3Smrg            if(new->prev) new->prev->next = new;
1663c582b7e3Smrg            last = new;
1664c582b7e3Smrg            if(!first) first = new;
1665c582b7e3Smrg            pScrn->display->virtualX =
1666c582b7e3Smrg            pScrn->virtualX = MAX(pScrn->virtualX, width);
1667c582b7e3Smrg            pScrn->display->virtualY =
1668c582b7e3Smrg            pScrn->virtualY = MAX(pScrn->virtualY, height);
1669c582b7e3Smrg            count++;
1670c582b7e3Smrg        }
1671c582b7e3Smrg        else
1672c582b7e3Smrg        {
1673c582b7e3Smrg            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1674c582b7e3Smrg                "Mode name %s is invalid\n", pScrn->display->modes[i]);
1675c582b7e3Smrg            continue;
1676c582b7e3Smrg        }
1677c582b7e3Smrg   }
1678c582b7e3Smrg
1679c582b7e3Smrg   if(last)
1680c582b7e3Smrg   {
1681c582b7e3Smrg       last->next = first;
1682c582b7e3Smrg       first->prev = last;
1683c582b7e3Smrg       pScrn->modes = first;
1684c582b7e3Smrg
1685c582b7e3Smrg       /*FIXME: May need to validate line pitch here*/
1686c582b7e3Smrg       {
1687c582b7e3Smrg           int dummy = 0;
1688c582b7e3Smrg           switch(pScrn->depth / 8)
1689c582b7e3Smrg           {
1690c582b7e3Smrg              case 1:
1691c582b7e3Smrg                  dummy = 128 - pScrn->virtualX % 128;
1692c582b7e3Smrg                  break;
1693c582b7e3Smrg              case 2:
1694c582b7e3Smrg                  dummy = 32 - pScrn->virtualX % 32;
1695c582b7e3Smrg                  break;
1696c582b7e3Smrg              case 3:
1697c582b7e3Smrg              case 4:
1698c582b7e3Smrg                  dummy = 16 - pScrn->virtualX % 16;
1699c582b7e3Smrg           }
1700c582b7e3Smrg           pScrn->displayWidth = pScrn->virtualX + dummy;
1701c582b7e3Smrg       }
1702c582b7e3Smrg
1703c582b7e3Smrg   }
1704c582b7e3Smrg
1705c582b7e3Smrg   return count;
1706c582b7e3Smrg}
1707c582b7e3Smrg
1708c582b7e3Smrg
1709c582b7e3Smrg/* This is called by R128PreInit to validate modes and compute parameters
1710c582b7e3Smrg   for all of the valid modes. */
1711c582b7e3Smrgstatic Bool R128PreInitModes(ScrnInfoPtr pScrn)
1712c582b7e3Smrg{
1713c582b7e3Smrg    R128InfoPtr   info = R128PTR(pScrn);
1714c582b7e3Smrg    ClockRangePtr clockRanges;
1715c582b7e3Smrg    int           modesFound;
1716c582b7e3Smrg
1717c582b7e3Smrg    if(info->isDFP) {
1718c582b7e3Smrg        R128MapMem(pScrn);
1719c582b7e3Smrg        info->BIOSDisplay = R128_BIOS_DISPLAY_FP;
1720c582b7e3Smrg        /* validate if DFP really connected. */
1721c582b7e3Smrg        if(!R128GetDFPInfo(pScrn)) {
1722c582b7e3Smrg            info->isDFP = FALSE;
1723c582b7e3Smrg            info->BIOSDisplay = R128_BIOS_DISPLAY_CRT;
1724c582b7e3Smrg        } else if(!info->isPro2) {
1725c582b7e3Smrg            /* RageProII doesn't support rmx, we can't use native-mode
1726c582b7e3Smrg               stretching for other non-native modes. It will rely on
1727c582b7e3Smrg               whatever VESA modes monitor can support. */
1728c582b7e3Smrg            modesFound = R128ValidateFPModes(pScrn);
1729c582b7e3Smrg            if(modesFound < 1) {
1730c582b7e3Smrg                 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1731c582b7e3Smrg                     "No valid mode found for this DFP/LCD\n");
1732c582b7e3Smrg                 R128UnmapMem(pScrn);
1733c582b7e3Smrg                 return FALSE;
1734c582b7e3Smrg
1735c582b7e3Smrg            }
1736c582b7e3Smrg        }
1737c582b7e3Smrg        R128UnmapMem(pScrn);
1738c582b7e3Smrg    }
1739c582b7e3Smrg
1740c582b7e3Smrg    if(!info->isDFP || info->isPro2) {
1741c582b7e3Smrg				/* Get mode information */
1742c582b7e3Smrg        pScrn->progClock                   = TRUE;
1743c582b7e3Smrg        clockRanges                        = xnfcalloc(sizeof(*clockRanges), 1);
1744c582b7e3Smrg        clockRanges->next                  = NULL;
1745c582b7e3Smrg        clockRanges->minClock              = info->pll.min_pll_freq;
1746c582b7e3Smrg        clockRanges->maxClock              = info->pll.max_pll_freq * 10;
1747c582b7e3Smrg        clockRanges->clockIndex            = -1;
1748c582b7e3Smrg        if (info->HasPanelRegs || info->isDFP) {
1749c582b7e3Smrg            clockRanges->interlaceAllowed  = FALSE;
1750c582b7e3Smrg            clockRanges->doubleScanAllowed = FALSE;
1751c582b7e3Smrg        } else {
1752c582b7e3Smrg            clockRanges->interlaceAllowed  = TRUE;
1753c582b7e3Smrg            clockRanges->doubleScanAllowed = TRUE;
1754c582b7e3Smrg        }
1755c582b7e3Smrg
1756c582b7e3Smrg        if(pScrn->monitor->DDC) {
1757c582b7e3Smrg        /*if we still don't know sync range yet, let's try EDID.
1758c582b7e3Smrg          Note that, since we can have dual heads, the Xconfigurator
1759c582b7e3Smrg          may not be able to probe both monitors correctly through
1760c582b7e3Smrg          vbe probe function (R128ProbeDDC). Here we provide an
1761c582b7e3Smrg          additional way to auto-detect sync ranges if they haven't
1762c582b7e3Smrg          been added to XF86Config manually.
1763c582b7e3Smrg        **/
1764c582b7e3Smrg            if(pScrn->monitor->nHsync <= 0)
1765c582b7e3Smrg                R128SetSyncRangeFromEdid(pScrn, 1);
1766c582b7e3Smrg            if(pScrn->monitor->nVrefresh <= 0)
1767c582b7e3Smrg                R128SetSyncRangeFromEdid(pScrn, 0);
1768c582b7e3Smrg        }
1769c582b7e3Smrg
1770c582b7e3Smrg        modesFound = xf86ValidateModes(pScrn,
1771c582b7e3Smrg				   pScrn->monitor->Modes,
1772c582b7e3Smrg				   pScrn->display->modes,
1773c582b7e3Smrg				   clockRanges,
1774c582b7e3Smrg				   NULL,        /* linePitches */
1775c582b7e3Smrg				   8 * 64,      /* minPitch */
1776c582b7e3Smrg				   8 * 1024,    /* maxPitch */
1777c582b7e3Smrg/*
1778c582b7e3Smrg * ATI docs say pitchInc must be 8 * 64, but this doesn't permit a pitch of
1779c582b7e3Smrg * 800 bytes, which is known to work on the Rage128 LF on clamshell iBooks
1780c582b7e3Smrg */
1781c582b7e3Smrg				   8 * 32,      /* pitchInc */
1782c582b7e3Smrg				   128,         /* minHeight */
1783c582b7e3Smrg				   2048,        /* maxHeight */
1784c582b7e3Smrg				   pScrn->display->virtualX,
1785c582b7e3Smrg				   pScrn->display->virtualY,
1786c582b7e3Smrg				   info->FbMapSize,
1787c582b7e3Smrg				   LOOKUP_BEST_REFRESH);
178879e5230eSmacallan#ifndef AVOID_FBDEV
1789c582b7e3Smrg        if (modesFound < 1 && info->FBDev) {
1790c582b7e3Smrg		fbdevHWUseBuildinMode(pScrn);
179179e5230eSmacallan		pScrn->displayWidth = fbdevHWGetLineLength(pScrn) /
179279e5230eSmacallan		    (pScrn->bitsPerPixel / 8);
1793c582b7e3Smrg		modesFound = 1;
1794c582b7e3Smrg        }
179579e5230eSmacallan#endif
1796c582b7e3Smrg
1797c582b7e3Smrg        if (modesFound == -1) return FALSE;
1798c582b7e3Smrg        xf86PruneDriverModes(pScrn);
1799c582b7e3Smrg        if (!modesFound || !pScrn->modes) {
1800c582b7e3Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
1801c582b7e3Smrg            return FALSE;
1802c582b7e3Smrg        }
1803c582b7e3Smrg        xf86SetCrtcForModes(pScrn, 0);
1804c582b7e3Smrg    }
1805c582b7e3Smrg				/* Set DPI */
1806c582b7e3Smrg    pScrn->currentMode = pScrn->modes;
1807c582b7e3Smrg    xf86PrintModes(pScrn);
1808c582b7e3Smrg
1809c582b7e3Smrg    xf86SetDpi(pScrn, 0, 0);
1810c582b7e3Smrg
1811c582b7e3Smrg				/* Get ScreenInit function */
1812c582b7e3Smrg    if (!xf86LoadSubModule(pScrn, "fb")) return FALSE;
1813c582b7e3Smrg
1814c582b7e3Smrg    info->CurrentLayout.displayWidth = pScrn->displayWidth;
1815c582b7e3Smrg    info->CurrentLayout.mode = pScrn->currentMode;
1816c582b7e3Smrg
1817c582b7e3Smrg    return TRUE;
1818c582b7e3Smrg}
1819c582b7e3Smrg
1820c582b7e3Smrg/* This is called by R128PreInit to initialize the hardware cursor. */
1821c582b7e3Smrgstatic Bool R128PreInitCursor(ScrnInfoPtr pScrn)
1822c582b7e3Smrg{
1823c582b7e3Smrg    R128InfoPtr   info = R128PTR(pScrn);
1824c582b7e3Smrg
1825c582b7e3Smrg    if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) {
1826c582b7e3Smrg	if (!xf86LoadSubModule(pScrn, "ramdac")) return FALSE;
1827c582b7e3Smrg    }
1828c582b7e3Smrg    return TRUE;
1829c582b7e3Smrg}
1830c582b7e3Smrg
1831c582b7e3Smrgstatic Bool R128PreInitInt10(ScrnInfoPtr pScrn, xf86Int10InfoPtr *ppInt10)
1832c582b7e3Smrg{
1833c582b7e3Smrg    R128InfoPtr   info = R128PTR(pScrn);
1834c582b7e3Smrg#if 1 && !defined(__alpha__)
1835c582b7e3Smrg    /* int10 is broken on some Alphas */
1836c582b7e3Smrg    if (xf86LoadSubModule(pScrn, "int10")) {
1837c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex,X_INFO,"initializing int10\n");
1838c582b7e3Smrg	*ppInt10 = xf86InitInt10(info->pEnt->index);
1839c582b7e3Smrg    }
1840c582b7e3Smrg#endif
1841c582b7e3Smrg    return TRUE;
1842c582b7e3Smrg}
1843c582b7e3Smrg
184484354367Smrg#ifdef R128DRI
1845c582b7e3Smrgstatic Bool R128PreInitDRI(ScrnInfoPtr pScrn)
1846c582b7e3Smrg{
1847c582b7e3Smrg    R128InfoPtr   info = R128PTR(pScrn);
1848c582b7e3Smrg
1849c582b7e3Smrg    if (xf86ReturnOptValBool(info->Options, OPTION_CCE_PIO, FALSE)) {
1850c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forcing CCE into PIO mode\n");
1851c582b7e3Smrg	info->CCEMode = R128_DEFAULT_CCE_PIO_MODE;
1852c582b7e3Smrg    } else {
1853c582b7e3Smrg	info->CCEMode = R128_DEFAULT_CCE_BM_MODE;
1854c582b7e3Smrg    }
1855c582b7e3Smrg
1856c582b7e3Smrg    if (xf86ReturnOptValBool(info->Options, OPTION_NO_SECURITY, FALSE)) {
1857c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1858c582b7e3Smrg		   "WARNING!!!  CCE Security checks disabled!!! **********\n");
1859c582b7e3Smrg	info->CCESecure = FALSE;
1860c582b7e3Smrg    } else {
1861c582b7e3Smrg	info->CCESecure = TRUE;
1862c582b7e3Smrg    }
1863c582b7e3Smrg
1864c582b7e3Smrg    info->agpMode        = R128_DEFAULT_AGP_MODE;
1865c582b7e3Smrg    info->agpSize        = R128_DEFAULT_AGP_SIZE;
1866c582b7e3Smrg    info->ringSize       = R128_DEFAULT_RING_SIZE;
1867c582b7e3Smrg    info->bufSize        = R128_DEFAULT_BUFFER_SIZE;
1868c582b7e3Smrg    info->agpTexSize     = R128_DEFAULT_AGP_TEX_SIZE;
1869c582b7e3Smrg
1870c582b7e3Smrg    info->CCEusecTimeout = R128_DEFAULT_CCE_TIMEOUT;
1871c582b7e3Smrg
1872c582b7e3Smrg    if (!info->IsPCI) {
1873c582b7e3Smrg	if (xf86GetOptValInteger(info->Options,
1874c582b7e3Smrg				 OPTION_AGP_MODE, &(info->agpMode))) {
1875c582b7e3Smrg	    if (info->agpMode < 1 || info->agpMode > R128_AGP_MAX_MODE) {
1876c582b7e3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1877c582b7e3Smrg			   "Illegal AGP Mode: %d\n", info->agpMode);
1878c582b7e3Smrg		return FALSE;
1879c582b7e3Smrg	    }
1880c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1881c582b7e3Smrg		       "Using AGP %dx mode\n", info->agpMode);
1882c582b7e3Smrg	}
1883c582b7e3Smrg
1884c582b7e3Smrg	if (xf86GetOptValInteger(info->Options,
1885c582b7e3Smrg				 OPTION_AGP_SIZE, (int *)&(info->agpSize))) {
1886c582b7e3Smrg	    switch (info->agpSize) {
1887c582b7e3Smrg	    case 4:
1888c582b7e3Smrg	    case 8:
1889c582b7e3Smrg	    case 16:
1890c582b7e3Smrg	    case 32:
1891c582b7e3Smrg	    case 64:
1892c582b7e3Smrg	    case 128:
1893c582b7e3Smrg	    case 256:
1894c582b7e3Smrg		break;
1895c582b7e3Smrg	    default:
1896c582b7e3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1897c582b7e3Smrg			   "Illegal AGP size: %d MB\n", info->agpSize);
1898c582b7e3Smrg		return FALSE;
1899c582b7e3Smrg	    }
1900c582b7e3Smrg	}
1901c582b7e3Smrg
1902c582b7e3Smrg	if (xf86GetOptValInteger(info->Options,
1903c582b7e3Smrg				 OPTION_RING_SIZE, &(info->ringSize))) {
1904c582b7e3Smrg	    if (info->ringSize < 1 || info->ringSize >= (int)info->agpSize) {
1905c582b7e3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1906c582b7e3Smrg			   "Illegal ring buffer size: %d MB\n",
1907c582b7e3Smrg			   info->ringSize);
1908c582b7e3Smrg		return FALSE;
1909c582b7e3Smrg	    }
1910c582b7e3Smrg	}
1911c582b7e3Smrg
1912c582b7e3Smrg	if (xf86GetOptValInteger(info->Options,
1913c582b7e3Smrg				 OPTION_BUFFER_SIZE, &(info->bufSize))) {
1914c582b7e3Smrg	    if (info->bufSize < 1 || info->bufSize >= (int)info->agpSize) {
1915c582b7e3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1916c582b7e3Smrg			   "Illegal vertex/indirect buffers size: %d MB\n",
1917c582b7e3Smrg			   info->bufSize);
1918c582b7e3Smrg		return FALSE;
1919c582b7e3Smrg	    }
1920c582b7e3Smrg	    if (info->bufSize > 2) {
1921c582b7e3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1922c582b7e3Smrg			   "Illegal vertex/indirect buffers size: %d MB\n",
1923c582b7e3Smrg			   info->bufSize);
1924c582b7e3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1925c582b7e3Smrg			   "Clamping vertex/indirect buffers size to 2 MB\n");
1926c582b7e3Smrg		info->bufSize = 2;
1927c582b7e3Smrg	    }
1928c582b7e3Smrg	}
1929c582b7e3Smrg
1930c582b7e3Smrg	if (info->ringSize + info->bufSize + info->agpTexSize >
1931c582b7e3Smrg	    (int)info->agpSize) {
1932c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1933c582b7e3Smrg		       "Buffers are too big for requested AGP space\n");
1934c582b7e3Smrg	    return FALSE;
1935c582b7e3Smrg	}
1936c582b7e3Smrg
1937c582b7e3Smrg	info->agpTexSize = info->agpSize - (info->ringSize + info->bufSize);
1938c582b7e3Smrg    }
1939c582b7e3Smrg
1940c582b7e3Smrg    if (xf86GetOptValInteger(info->Options, OPTION_USEC_TIMEOUT,
1941c582b7e3Smrg			     &(info->CCEusecTimeout))) {
1942c582b7e3Smrg	/* This option checked by the R128 DRM kernel module */
1943c582b7e3Smrg    }
1944c582b7e3Smrg
1945c582b7e3Smrg    if (!xf86LoadSubModule(pScrn, "shadowfb")) {
1946c582b7e3Smrg	info->allowPageFlip = 0;
1947c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1948c582b7e3Smrg		   "Couldn't load shadowfb module:\n");
1949c582b7e3Smrg    } else {
1950c582b7e3Smrg	info->allowPageFlip = xf86ReturnOptValBool(info->Options,
1951c582b7e3Smrg						   OPTION_PAGE_FLIP,
1952c582b7e3Smrg						   FALSE);
1953c582b7e3Smrg    }
1954c582b7e3Smrg
1955c582b7e3Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Page flipping %sabled\n",
1956c582b7e3Smrg	       info->allowPageFlip ? "en" : "dis");
1957c582b7e3Smrg
1958c582b7e3Smrg    return TRUE;
1959c582b7e3Smrg}
1960c582b7e3Smrg#endif
1961c582b7e3Smrg
1962c582b7e3Smrgstatic void
1963c582b7e3SmrgR128ProbeDDC(ScrnInfoPtr pScrn, int indx)
1964c582b7e3Smrg{
1965c582b7e3Smrg    vbeInfoPtr pVbe;
1966c582b7e3Smrg    if (xf86LoadSubModule(pScrn, "vbe")) {
1967c582b7e3Smrg	pVbe = VBEInit(NULL,indx);
1968c582b7e3Smrg	ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
1969c582b7e3Smrg	vbeFree(pVbe);
1970c582b7e3Smrg    }
1971c582b7e3Smrg}
1972c582b7e3Smrg
1973c582b7e3Smrg/* R128PreInit is called once at server startup. */
1974c582b7e3SmrgBool R128PreInit(ScrnInfoPtr pScrn, int flags)
1975c582b7e3Smrg{
1976c582b7e3Smrg    R128InfoPtr      info;
1977c582b7e3Smrg    xf86Int10InfoPtr pInt10 = NULL;
1978c582b7e3Smrg
1979c582b7e3Smrg    R128TRACE(("R128PreInit\n"));
1980c582b7e3Smrg
1981c582b7e3Smrg    if (pScrn->numEntities != 1) return FALSE;
1982c582b7e3Smrg
1983c582b7e3Smrg    if (!R128GetRec(pScrn)) return FALSE;
1984c582b7e3Smrg
1985c582b7e3Smrg    info               = R128PTR(pScrn);
1986c582b7e3Smrg
1987c582b7e3Smrg    info->IsSecondary  = FALSE;
1988c582b7e3Smrg    info->IsPrimary = FALSE;
1989c582b7e3Smrg    info->SwitchingMode = FALSE;
1990c582b7e3Smrg
1991c582b7e3Smrg    info->pEnt         = xf86GetEntityInfo(pScrn->entityList[0]);
1992c582b7e3Smrg    if (info->pEnt->location.type != BUS_PCI) goto fail;
1993c582b7e3Smrg
1994c582b7e3Smrg    if(xf86IsEntityShared(pScrn->entityList[0]))
1995c582b7e3Smrg    {
1996c582b7e3Smrg        if(xf86IsPrimInitDone(pScrn->entityList[0]))
1997c582b7e3Smrg        {
1998c582b7e3Smrg            DevUnion* pPriv;
1999c582b7e3Smrg            R128EntPtr pR128Ent;
2000c582b7e3Smrg            info->IsSecondary = TRUE;
2001c582b7e3Smrg            pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
2002c582b7e3Smrg                    getR128EntityIndex());
2003c582b7e3Smrg            pR128Ent = pPriv->ptr;
2004c582b7e3Smrg            if(pR128Ent->BypassSecondary) return FALSE;
2005c582b7e3Smrg            pR128Ent->pSecondaryScrn = pScrn;
2006c582b7e3Smrg        }
2007c582b7e3Smrg        else
2008c582b7e3Smrg        {
2009c582b7e3Smrg            DevUnion* pPriv;
2010c582b7e3Smrg            R128EntPtr pR128Ent;
2011c582b7e3Smrg	    info->IsPrimary = TRUE;
2012c582b7e3Smrg            xf86SetPrimInitDone(pScrn->entityList[0]);
2013c582b7e3Smrg            pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
2014c582b7e3Smrg                    getR128EntityIndex());
2015c582b7e3Smrg            pR128Ent = pPriv->ptr;
2016c582b7e3Smrg            pR128Ent->pPrimaryScrn = pScrn;
2017c582b7e3Smrg            pR128Ent->IsDRIEnabled = FALSE;
2018c582b7e3Smrg            pR128Ent->BypassSecondary = FALSE;
2019c582b7e3Smrg            pR128Ent->HasSecondary = FALSE;
2020c582b7e3Smrg            pR128Ent->RestorePrimary = FALSE;
2021c582b7e3Smrg            pR128Ent->IsSecondaryRestored = FALSE;
2022c582b7e3Smrg        }
2023c582b7e3Smrg    }
2024c582b7e3Smrg
2025c582b7e3Smrg    if (flags & PROBE_DETECT) {
2026c582b7e3Smrg	R128ProbeDDC(pScrn, info->pEnt->index);
2027c582b7e3Smrg	return TRUE;
2028c582b7e3Smrg    }
2029c582b7e3Smrg
2030c582b7e3Smrg    info->PciInfo      = xf86GetPciInfoForEntity(info->pEnt->index);
2031c582b7e3Smrg    info->PciTag       = pciTag(PCI_DEV_BUS(info->PciInfo),
2032c582b7e3Smrg				PCI_DEV_DEV(info->PciInfo),
2033c582b7e3Smrg				PCI_DEV_FUNC(info->PciInfo));
2034c582b7e3Smrg
2035c582b7e3Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2036c582b7e3Smrg	       "PCI bus %d card %d func %d\n",
2037c582b7e3Smrg	       PCI_DEV_BUS(info->PciInfo),
2038c582b7e3Smrg	       PCI_DEV_DEV(info->PciInfo),
2039c582b7e3Smrg	       PCI_DEV_FUNC(info->PciInfo));
2040c582b7e3Smrg
204119019ffeSmrg#ifndef XSERVER_LIBPCIACCESS
2042c582b7e3Smrg    if (xf86RegisterResources(info->pEnt->index, 0, ResNone)) goto fail;
2043c582b7e3Smrg    if (xf86SetOperatingState(resVga, info->pEnt->index, ResUnusedOpr)) goto fail;
2044c582b7e3Smrg
2045c582b7e3Smrg    pScrn->racMemFlags = RAC_FB | RAC_COLORMAP | RAC_VIEWPORT | RAC_CURSOR;
204619019ffeSmrg#endif
2047c582b7e3Smrg    pScrn->monitor     = pScrn->confScreen->monitor;
2048c582b7e3Smrg
2049c582b7e3Smrg    if (!R128PreInitVisual(pScrn))    goto fail;
2050c582b7e3Smrg
2051c582b7e3Smrg				/* We can't do this until we have a
2052c582b7e3Smrg				   pScrn->display. */
2053c582b7e3Smrg    xf86CollectOptions(pScrn, NULL);
205484354367Smrg    if (!(info->Options = malloc(sizeof(R128Options))))    goto fail;
2055c582b7e3Smrg    memcpy(info->Options, R128Options, sizeof(R128Options));
2056c582b7e3Smrg    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, info->Options);
2057c582b7e3Smrg
2058c582b7e3Smrg    /* By default, don't do VGA IOs on ppc */
2059c582b7e3Smrg#if defined(__powerpc__) || defined(__sparc__) || !defined(WITH_VGAHW)
2060c582b7e3Smrg    info->VGAAccess = FALSE;
2061c582b7e3Smrg#else
2062c582b7e3Smrg    info->VGAAccess = TRUE;
2063c582b7e3Smrg#endif
2064c582b7e3Smrg
2065c582b7e3Smrg#ifdef WITH_VGAHW
2066c582b7e3Smrg    xf86GetOptValBool(info->Options, OPTION_VGA_ACCESS, &info->VGAAccess);
2067c582b7e3Smrg    if (info->VGAAccess) {
2068c582b7e3Smrg       if (!xf86LoadSubModule(pScrn, "vgahw"))
2069c582b7e3Smrg           info->VGAAccess = FALSE;
2070c582b7e3Smrg        else {
2071c582b7e3Smrg            if (!vgaHWGetHWRec(pScrn))
2072c582b7e3Smrg               info->VGAAccess = FALSE;
2073c582b7e3Smrg       }
2074c582b7e3Smrg       if (!info->VGAAccess)
2075c582b7e3Smrg           xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Loading VGA module failed,"
2076c582b7e3Smrg                      " trying to run without it\n");
2077c582b7e3Smrg    } else
2078c582b7e3Smrg           xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VGAAccess option set to FALSE,"
2079c582b7e3Smrg                      " VGA module load skipped\n");
208084354367Smrg    if (info->VGAAccess) {
208184354367Smrg	vgaHWSetStdFuncs(VGAHWPTR(pScrn));
2082c582b7e3Smrg        vgaHWGetIOBase(VGAHWPTR(pScrn));
208384354367Smrg    }
2084c582b7e3Smrg#else
2085c582b7e3Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VGAHW support not compiled, VGA "
2086c582b7e3Smrg               "module load skipped\n");
2087c582b7e3Smrg#endif
2088c582b7e3Smrg
2089c582b7e3Smrg
2090c582b7e3Smrg
2091c582b7e3Smrg    if (!R128PreInitWeight(pScrn))    goto fail;
2092c582b7e3Smrg
2093c582b7e3Smrg    if(xf86GetOptValInteger(info->Options, OPTION_VIDEO_KEY, &(info->videoKey))) {
2094c582b7e3Smrg        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video key set to 0x%x\n",
2095c582b7e3Smrg                                info->videoKey);
2096c582b7e3Smrg    } else {
2097c582b7e3Smrg        info->videoKey = 0x1E;
2098c582b7e3Smrg    }
2099c582b7e3Smrg
2100c582b7e3Smrg    if (xf86ReturnOptValBool(info->Options, OPTION_SHOW_CACHE, FALSE)) {
2101c582b7e3Smrg        info->showCache = TRUE;
2102c582b7e3Smrg        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShowCache enabled\n");
2103c582b7e3Smrg    }
2104c582b7e3Smrg
210579e5230eSmacallan#ifndef AVOID_FBDEV
2106c582b7e3Smrg#ifdef __powerpc__
2107c582b7e3Smrg    if (xf86ReturnOptValBool(info->Options, OPTION_FBDEV, TRUE))
2108c582b7e3Smrg#else
2109c582b7e3Smrg    if (xf86ReturnOptValBool(info->Options, OPTION_FBDEV, FALSE))
2110c582b7e3Smrg#endif
2111c582b7e3Smrg    {
2112c582b7e3Smrg	info->FBDev = TRUE;
2113c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
2114c582b7e3Smrg		   "Using framebuffer device\n");
2115c582b7e3Smrg    }
2116c582b7e3Smrg
2117c582b7e3Smrg    if (info->FBDev) {
2118c582b7e3Smrg	/* check for linux framebuffer device */
2119c582b7e3Smrg	if (!xf86LoadSubModule(pScrn, "fbdevhw")) return FALSE;
2120c582b7e3Smrg	if (!fbdevHWInit(pScrn, info->PciInfo, NULL)) return FALSE;
2121c582b7e3Smrg	pScrn->SwitchMode    = fbdevHWSwitchModeWeak();
2122c582b7e3Smrg	pScrn->AdjustFrame   = fbdevHWAdjustFrameWeak();
2123c582b7e3Smrg	pScrn->ValidMode     = fbdevHWValidModeWeak();
2124c582b7e3Smrg    }
2125c582b7e3Smrg
2126c582b7e3Smrg    if (!info->FBDev)
212779e5230eSmacallan#endif /* !AVOID_FBDEV */
2128c582b7e3Smrg	if (!R128PreInitInt10(pScrn, &pInt10)) goto fail;
2129c582b7e3Smrg
2130c582b7e3Smrg    if (!R128PreInitConfig(pScrn))             goto fail;
2131c582b7e3Smrg
2132c582b7e3Smrg    if (!R128GetBIOSParameters(pScrn, pInt10)) goto fail;
2133c582b7e3Smrg
2134c582b7e3Smrg    if (!R128GetPLLParameters(pScrn))          goto fail;
2135c582b7e3Smrg
2136c582b7e3Smrg    /* Don't fail on this one */
2137c582b7e3Smrg    R128PreInitDDC(pScrn, pInt10);
2138c582b7e3Smrg
2139c582b7e3Smrg    if (!R128PreInitGamma(pScrn))              goto fail;
2140c582b7e3Smrg
2141c582b7e3Smrg    if (!R128PreInitModes(pScrn))              goto fail;
2142c582b7e3Smrg
2143c582b7e3Smrg    if (!R128PreInitCursor(pScrn))             goto fail;
2144c582b7e3Smrg
214584354367Smrg#ifdef R128DRI
2146c582b7e3Smrg    if (!R128PreInitDRI(pScrn))                goto fail;
2147c582b7e3Smrg#endif
2148c582b7e3Smrg
2149c582b7e3Smrg				/* Free the video bios (if applicable) */
2150c582b7e3Smrg    if (info->VBIOS) {
215184354367Smrg	free(info->VBIOS);
2152c582b7e3Smrg	info->VBIOS = NULL;
2153c582b7e3Smrg    }
2154c582b7e3Smrg
2155c582b7e3Smrg				/* Free int10 info */
2156c582b7e3Smrg    if (pInt10)
2157c582b7e3Smrg	xf86FreeInt10(pInt10);
2158c582b7e3Smrg
2159c582b7e3Smrg    xf86DrvMsg(pScrn->scrnIndex, X_NOTICE,
2160c582b7e3Smrg	"For information on using the multimedia capabilities\n\tof this"
2161c582b7e3Smrg	" adapter, please see http://gatos.sf.net.\n");
2162c582b7e3Smrg
2163c582b7e3Smrg    return TRUE;
2164c582b7e3Smrg
2165c582b7e3Smrg  fail:
2166c582b7e3Smrg				/* Pre-init failed. */
2167c582b7e3Smrg
2168c582b7e3Smrg				/* Free the video bios (if applicable) */
2169c582b7e3Smrg    if (info->VBIOS) {
217084354367Smrg	free(info->VBIOS);
2171c582b7e3Smrg	info->VBIOS = NULL;
2172c582b7e3Smrg    }
2173c582b7e3Smrg
2174c582b7e3Smrg				/* Free int10 info */
2175c582b7e3Smrg    if (pInt10)
2176c582b7e3Smrg	xf86FreeInt10(pInt10);
2177c582b7e3Smrg
2178c582b7e3Smrg#ifdef WITH_VGAHW
2179c582b7e3Smrg    if (info->VGAAccess)
2180c582b7e3Smrg           vgaHWFreeHWRec(pScrn);
2181c582b7e3Smrg#endif
2182c582b7e3Smrg    R128FreeRec(pScrn);
2183c582b7e3Smrg    return FALSE;
2184c582b7e3Smrg}
2185c582b7e3Smrg
2186c582b7e3Smrg/* Load a palette. */
2187c582b7e3Smrgstatic void R128LoadPalette(ScrnInfoPtr pScrn, int numColors,
2188c582b7e3Smrg			    int *indices, LOCO *colors, VisualPtr pVisual)
2189c582b7e3Smrg{
2190c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
2191c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
2192c582b7e3Smrg    int           i, j;
2193c582b7e3Smrg    int           idx;
2194c582b7e3Smrg    unsigned char r, g, b;
2195c582b7e3Smrg
2196c582b7e3Smrg    /* If the second monitor is connected, we also
2197c582b7e3Smrg       need to deal with the secondary palette*/
2198c582b7e3Smrg    if (info->IsSecondary) j = 1;
2199c582b7e3Smrg    else j = 0;
2200c582b7e3Smrg
2201c582b7e3Smrg    PAL_SELECT(j);
2202c582b7e3Smrg
2203c582b7e3Smrg
2204c582b7e3Smrg    /* Select palette 0 (main CRTC) if using FP-enabled chip */
2205c582b7e3Smrg    /*if (info->HasPanelRegs || info->isDFP) PAL_SELECT(0);*/
2206c582b7e3Smrg
2207c582b7e3Smrg    if (info->CurrentLayout.depth == 15) {
2208c582b7e3Smrg	/* 15bpp mode.  This sends 32 values. */
2209c582b7e3Smrg	for (i = 0; i < numColors; i++) {
2210c582b7e3Smrg	    idx = indices[i];
2211c582b7e3Smrg	    r   = colors[idx].red;
2212c582b7e3Smrg	    g   = colors[idx].green;
2213c582b7e3Smrg	    b   = colors[idx].blue;
2214c582b7e3Smrg	    OUTPAL(idx * 8, r, g, b);
2215c582b7e3Smrg	}
2216c582b7e3Smrg    }
2217c582b7e3Smrg    else if (info->CurrentLayout.depth == 16) {
2218c582b7e3Smrg	/* 16bpp mode.  This sends 64 values. */
2219c582b7e3Smrg				/* There are twice as many green values as
2220c582b7e3Smrg				   there are values for red and blue.  So,
2221c582b7e3Smrg				   we take each red and blue pair, and
2222c582b7e3Smrg				   combine it with each of the two green
2223c582b7e3Smrg				   values. */
2224c582b7e3Smrg	for (i = 0; i < numColors; i++) {
2225c582b7e3Smrg	    idx = indices[i];
2226c582b7e3Smrg	    r   = colors[idx / 2].red;
2227c582b7e3Smrg	    g   = colors[idx].green;
2228c582b7e3Smrg	    b   = colors[idx / 2].blue;
2229c582b7e3Smrg	    OUTPAL(idx * 4, r, g, b);
2230c582b7e3Smrg	}
2231c582b7e3Smrg    }
2232c582b7e3Smrg    else {
2233c582b7e3Smrg	/* 8bpp mode.  This sends 256 values. */
2234c582b7e3Smrg	for (i = 0; i < numColors; i++) {
2235c582b7e3Smrg	    idx = indices[i];
2236c582b7e3Smrg	    r   = colors[idx].red;
2237c582b7e3Smrg	    b   = colors[idx].blue;
2238c582b7e3Smrg	    g   = colors[idx].green;
2239c582b7e3Smrg	    OUTPAL(idx, r, g, b);
2240c582b7e3Smrg	}
2241c582b7e3Smrg    }
2242c582b7e3Smrg}
2243c582b7e3Smrg
2244c582b7e3Smrgstatic void
224584354367SmrgR128BlockHandler(BLOCKHANDLER_ARGS_DECL)
2246c582b7e3Smrg{
224784354367Smrg    SCREEN_PTR(arg);
224884354367Smrg    ScrnInfoPtr pScrn   = xf86ScreenToScrn(pScreen);
2249c582b7e3Smrg    R128InfoPtr info    = R128PTR(pScrn);
2250c582b7e3Smrg
225184354367Smrg#ifdef R128DRI
2252c582b7e3Smrg    if (info->directRenderingEnabled)
2253c582b7e3Smrg        FLUSH_RING();
2254c582b7e3Smrg#endif
2255c582b7e3Smrg
2256c582b7e3Smrg    pScreen->BlockHandler = info->BlockHandler;
225784354367Smrg    (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
2258c582b7e3Smrg    pScreen->BlockHandler = R128BlockHandler;
2259c582b7e3Smrg
2260c582b7e3Smrg    if(info->VideoTimerCallback) {
2261c582b7e3Smrg        (*info->VideoTimerCallback)(pScrn, currentTime.milliseconds);
2262c582b7e3Smrg    }
2263c582b7e3Smrg}
2264c582b7e3Smrg
226584354367Smrg#ifdef USE_EXA
226684354367SmrgBool R128VerboseInitEXA(ScreenPtr pScreen)
226784354367Smrg{
226884354367Smrg    ScrnInfoPtr pScrn  = xf86ScreenToScrn(pScreen);
226984354367Smrg    R128InfoPtr info   = R128PTR(pScrn);
227084354367Smrg
227184354367Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Going to init EXA...\n");
227284354367Smrg
227384354367Smrg    if (R128EXAInit(pScreen)) {
227484354367Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "EXA Acceleration enabled\n");
227584354367Smrg	info->accelOn = TRUE;
227684354367Smrg
227784354367Smrg	return TRUE;
227884354367Smrg    } else {
227984354367Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
228084354367Smrg		   "EXA Acceleration initialization failed\n");
228184354367Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "EXA Acceleration disabled\n");
228284354367Smrg	info->accelOn = FALSE;
228384354367Smrg
228484354367Smrg	return FALSE;
228584354367Smrg    }
228684354367Smrg}
228784354367Smrg#endif
228884354367Smrg
228984354367Smrgvoid R128VerboseInitAccel(Bool noAccel, ScreenPtr pScreen)
229084354367Smrg{
229184354367Smrg    ScrnInfoPtr pScrn  = xf86ScreenToScrn(pScreen);
229284354367Smrg    R128InfoPtr info   = R128PTR(pScrn);
229384354367Smrg
229484354367Smrg    if (!noAccel) {
229584354367Smrg	if (R128AccelInit(pScreen)) {
229684354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Acceleration enabled\n");
229784354367Smrg	    info->accelOn = TRUE;
229884354367Smrg	} else {
229984354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
230084354367Smrg		       "Acceleration initialization failed\n");
230184354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Acceleration disabled\n");
230284354367Smrg	    info->accelOn = FALSE;
230384354367Smrg	}
230484354367Smrg    } else {
230584354367Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Acceleration disabled\n");
230684354367Smrg	info->accelOn = FALSE;
230784354367Smrg    }
230884354367Smrg}
230984354367Smrg
2310c582b7e3Smrg/* Called at the start of each server generation. */
231184354367SmrgBool R128ScreenInit(SCREEN_INIT_ARGS_DECL)
2312c582b7e3Smrg{
231384354367Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
2314c582b7e3Smrg    R128InfoPtr info   = R128PTR(pScrn);
2315c582b7e3Smrg    BoxRec      MemBox;
231684354367Smrg    int width_bytes = (pScrn->displayWidth *
231784354367Smrg			   info->CurrentLayout.pixel_bytes);
231884354367Smrg    int         x1 = 0, x2 = 0, y1 = 0, y2 = 0;
231984354367Smrg    Bool	noAccel;
232084354367Smrg#ifdef USE_EXA
232184354367Smrg    ExaOffscreenArea*     osArea = NULL;
232284354367Smrg#else
232384354367Smrg    void*		  osArea = NULL;
232484354367Smrg#endif
232584354367Smrg    char *optstr;
2326c582b7e3Smrg
2327c582b7e3Smrg    R128TRACE(("R128ScreenInit %x %d\n", pScrn->memPhysBase, pScrn->fbOffset));
232884354367Smrg    info->useEXA = FALSE;
232984354367Smrg#ifdef USE_EXA
233084354367Smrg#ifndef HAVE_XAA_H
233184354367Smrg    info->useEXA = TRUE;
233284354367Smrg#endif
233384354367Smrg#endif
233484354367Smrg
233584354367Smrg#ifdef USE_EXA
233684354367Smrg    optstr = (char *)xf86GetOptValString(info->Options, OPTION_ACCELMETHOD);
233784354367Smrg    if (optstr != NULL) {
233884354367Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "AccelMethod option found\n");
233984354367Smrg	if (xf86NameCmp(optstr, "EXA") == 0) {
234084354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "AccelMethod is set to EXA, turning EXA on\n");
234184354367Smrg	    info->useEXA = TRUE;
234284354367Smrg	}
234384354367Smrg    }
234484354367Smrg#ifdef RENDER
234584354367Smrg    info->RenderAccel = xf86ReturnOptValBool(info->Options, OPTION_RENDERACCEL, TRUE);
234684354367Smrg    if (info->RenderAccel)
2347a0e1ef58Smrg        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Acceleration of RENDER operations will be enabled "
234884354367Smrg					     "upon successful loading of DRI and EXA\n");
234984354367Smrg#endif
235084354367Smrg#endif
2351c582b7e3Smrg
235284354367Smrg#ifdef R128DRI
2353c582b7e3Smrg				/* Turn off the CCE for now. */
2354c582b7e3Smrg    info->CCEInUse     = FALSE;
2355c582b7e3Smrg    info->indirectBuffer = NULL;
2356c582b7e3Smrg#endif
2357c582b7e3Smrg
2358c582b7e3Smrg    if (!R128MapMem(pScrn)) return FALSE;
2359c582b7e3Smrg    pScrn->fbOffset    = 0;
2360c582b7e3Smrg    if(info->IsSecondary) pScrn->fbOffset = pScrn->videoRam * 1024;
236184354367Smrg#ifdef R128DRI
2362c582b7e3Smrg    info->fbX          = 0;
2363c582b7e3Smrg    info->fbY          = 0;
2364c582b7e3Smrg    info->frontOffset  = 0;
2365c582b7e3Smrg    info->frontPitch   = pScrn->displayWidth;
2366c582b7e3Smrg#endif
2367c582b7e3Smrg
2368c582b7e3Smrg    info->PaletteSavedOnVT = FALSE;
2369c582b7e3Smrg
2370c582b7e3Smrg    R128Save(pScrn);
237179e5230eSmacallan#ifndef AVOID_FBDEV
2372c582b7e3Smrg    if (info->FBDev) {
2373c582b7e3Smrg	if (!fbdevHWModeInit(pScrn, pScrn->currentMode)) return FALSE;
237479e5230eSmacallan    } else
237579e5230eSmacallan#endif
2376c582b7e3Smrg	if (!R128ModeInit(pScrn, pScrn->currentMode)) return FALSE;
2377c582b7e3Smrg
2378c582b7e3Smrg    R128SaveScreen(pScreen, SCREEN_SAVER_ON);
237984354367Smrg    pScrn->AdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
2380c582b7e3Smrg
2381c582b7e3Smrg				/* Visual setup */
2382c582b7e3Smrg    miClearVisualTypes();
2383c582b7e3Smrg    if (!miSetVisualTypes(pScrn->depth,
2384c582b7e3Smrg			  miGetDefaultVisualMask(pScrn->depth),
2385c582b7e3Smrg			  pScrn->rgbBits,
2386c582b7e3Smrg			  pScrn->defaultVisual)) return FALSE;
2387c582b7e3Smrg    miSetPixmapDepths ();
2388c582b7e3Smrg
238984354367Smrg    noAccel = xf86ReturnOptValBool(info->Options, OPTION_NOACCEL, FALSE);
239084354367Smrg
239184354367Smrg#ifdef R128DRI
2392c582b7e3Smrg				/* Setup DRI after visuals have been
2393c582b7e3Smrg				   established, but before fbScreenInit is
2394c582b7e3Smrg				   called.  fbScreenInit will eventually
2395c582b7e3Smrg				   call the driver's InitGLXVisuals call
2396c582b7e3Smrg				   back. */
2397c582b7e3Smrg    {
2398c582b7e3Smrg	/* FIXME: When we move to dynamic allocation of back and depth
2399c582b7e3Smrg	   buffers, we will want to revisit the following check for 3
2400c582b7e3Smrg	   times the virtual size of the screen below. */
2401c582b7e3Smrg	int maxy        = info->FbMapSize / width_bytes;
2402c582b7e3Smrg
240384354367Smrg	if (noAccel) {
240484354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2405c582b7e3Smrg		       "Acceleration disabled, not initializing the DRI\n");
2406c582b7e3Smrg	    info->directRenderingEnabled = FALSE;
2407c582b7e3Smrg	} else if (maxy <= pScrn->virtualY * 3) {
240884354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2409c582b7e3Smrg		       "Static buffer allocation failed -- "
2410c582b7e3Smrg		       "need at least %d kB video memory\n",
2411c582b7e3Smrg		       (pScrn->displayWidth * pScrn->virtualY *
2412c582b7e3Smrg			info->CurrentLayout.pixel_bytes * 3 + 1023) / 1024);
2413c582b7e3Smrg	    info->directRenderingEnabled = FALSE;
2414c582b7e3Smrg	} else {
2415c582b7e3Smrg            if(info->IsSecondary)
2416c582b7e3Smrg                info->directRenderingEnabled = FALSE;
2417c582b7e3Smrg            else
2418c582b7e3Smrg            {
2419c582b7e3Smrg                /* Xinerama has sync problem with DRI, disable it for now */
2420c582b7e3Smrg                if(xf86IsEntityShared(pScrn->entityList[0]))
2421c582b7e3Smrg                {
2422c582b7e3Smrg                    info->directRenderingEnabled = FALSE;
242384354367Smrg 	            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2424c582b7e3Smrg                        "Direct Rendering Disabled -- "
2425c582b7e3Smrg                        "Dual-head configuration is not working with DRI "
2426c582b7e3Smrg                        "at present.\nPlease use only one Device/Screen "
2427c582b7e3Smrg                        "section in your XFConfig file.\n");
2428c582b7e3Smrg                }
2429c582b7e3Smrg                else
2430c582b7e3Smrg                info->directRenderingEnabled =
2431c582b7e3Smrg                    R128DRIScreenInit(pScreen);
2432c582b7e3Smrg                if(xf86IsEntityShared(pScrn->entityList[0]))
2433c582b7e3Smrg                {
2434c582b7e3Smrg                    DevUnion* pPriv;
2435c582b7e3Smrg                    R128EntPtr pR128Ent;
2436c582b7e3Smrg                    pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
2437c582b7e3Smrg                        getR128EntityIndex());
2438c582b7e3Smrg                    pR128Ent = pPriv->ptr;
2439c582b7e3Smrg                    pR128Ent->IsDRIEnabled = info->directRenderingEnabled;
2440c582b7e3Smrg                }
2441c582b7e3Smrg            }
2442c582b7e3Smrg	}
2443c582b7e3Smrg    }
2444c582b7e3Smrg#endif
2445c582b7e3Smrg
2446c582b7e3Smrg    if (!fbScreenInit (pScreen, info->FB,
2447c582b7e3Smrg		       pScrn->virtualX, pScrn->virtualY,
2448c582b7e3Smrg		       pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth,
2449c582b7e3Smrg		       pScrn->bitsPerPixel))
2450c582b7e3Smrg	return FALSE;
2451c582b7e3Smrg
2452c582b7e3Smrg    xf86SetBlackWhitePixels(pScreen);
2453c582b7e3Smrg
2454c582b7e3Smrg    if (pScrn->bitsPerPixel > 8) {
2455c582b7e3Smrg	VisualPtr visual;
2456c582b7e3Smrg
2457c582b7e3Smrg	visual = pScreen->visuals + pScreen->numVisuals;
2458c582b7e3Smrg	while (--visual >= pScreen->visuals) {
2459c582b7e3Smrg	    if ((visual->class | DynamicClass) == DirectColor) {
2460c582b7e3Smrg		visual->offsetRed   = pScrn->offset.red;
2461c582b7e3Smrg		visual->offsetGreen = pScrn->offset.green;
2462c582b7e3Smrg		visual->offsetBlue  = pScrn->offset.blue;
2463c582b7e3Smrg		visual->redMask     = pScrn->mask.red;
2464c582b7e3Smrg		visual->greenMask   = pScrn->mask.green;
2465c582b7e3Smrg		visual->blueMask    = pScrn->mask.blue;
2466c582b7e3Smrg	    }
2467c582b7e3Smrg	}
2468c582b7e3Smrg    }
2469c582b7e3Smrg
2470c582b7e3Smrg    /* must be after RGB order fixed */
2471c582b7e3Smrg    fbPictureInit (pScreen, 0, 0);
2472c582b7e3Smrg
2473c582b7e3Smrg				/* Memory manager setup */
247484354367Smrg#ifdef R128DRI
2475c582b7e3Smrg    if (info->directRenderingEnabled) {
247684354367Smrg	FBAreaPtr fbarea = NULL;
2477c582b7e3Smrg	int cpp = info->CurrentLayout.pixel_bytes;
2478c582b7e3Smrg	int bufferSize = pScrn->virtualY * width_bytes;
2479c582b7e3Smrg	int l, total;
2480c582b7e3Smrg	int scanlines;
2481c582b7e3Smrg
2482c582b7e3Smrg	switch (info->CCEMode) {
2483c582b7e3Smrg	case R128_DEFAULT_CCE_PIO_MODE:
2484c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CCE in PIO mode\n");
2485c582b7e3Smrg	    break;
2486c582b7e3Smrg	case R128_DEFAULT_CCE_BM_MODE:
2487c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CCE in BM mode\n");
2488c582b7e3Smrg	    break;
2489c582b7e3Smrg	default:
2490c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CCE in UNKNOWN mode\n");
2491c582b7e3Smrg	    break;
2492c582b7e3Smrg	}
2493c582b7e3Smrg
2494c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2495c582b7e3Smrg		   "Using %d MB AGP aperture\n", info->agpSize);
2496c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2497c582b7e3Smrg		   "Using %d MB for the ring buffer\n", info->ringSize);
2498c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2499c582b7e3Smrg		   "Using %d MB for vertex/indirect buffers\n", info->bufSize);
2500c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2501c582b7e3Smrg		   "Using %d MB for AGP textures\n", info->agpTexSize);
2502c582b7e3Smrg
2503c582b7e3Smrg	/* Try for front, back, depth, and two framebuffers worth of
2504c582b7e3Smrg	 * pixmap cache.  Should be enough for a fullscreen background
2505c582b7e3Smrg	 * image plus some leftovers.
2506c582b7e3Smrg	 */
2507c582b7e3Smrg	info->textureSize = info->FbMapSize - 5 * bufferSize;
2508c582b7e3Smrg
2509c582b7e3Smrg	/* If that gives us less than half the available memory, let's
2510c582b7e3Smrg	 * be greedy and grab some more.  Sorry, I care more about 3D
2511c582b7e3Smrg	 * performance than playing nicely, and you'll get around a full
2512c582b7e3Smrg	 * framebuffer's worth of pixmap cache anyway.
2513c582b7e3Smrg	 */
2514c582b7e3Smrg	if (info->textureSize < (int)info->FbMapSize / 2) {
2515c582b7e3Smrg	    info->textureSize = info->FbMapSize - 4 * bufferSize;
2516c582b7e3Smrg	}
2517c582b7e3Smrg
2518c582b7e3Smrg	if (info->textureSize > 0) {
2519c582b7e3Smrg	    l = R128MinBits((info->textureSize-1) / R128_NR_TEX_REGIONS);
2520c582b7e3Smrg	    if (l < R128_LOG_TEX_GRANULARITY) l = R128_LOG_TEX_GRANULARITY;
2521c582b7e3Smrg
2522c582b7e3Smrg	    /* Round the texture size up to the nearest whole number of
2523c582b7e3Smrg	     * texture regions.  Again, be greedy about this, don't
2524c582b7e3Smrg	     * round down.
2525c582b7e3Smrg	     */
2526c582b7e3Smrg	    info->log2TexGran = l;
2527c582b7e3Smrg	    info->textureSize = (info->textureSize >> l) << l;
2528c582b7e3Smrg	} else {
2529c582b7e3Smrg	    info->textureSize = 0;
2530c582b7e3Smrg	}
2531c582b7e3Smrg
2532c582b7e3Smrg	/* Set a minimum usable local texture heap size.  This will fit
2533c582b7e3Smrg	 * two 256x256x32bpp textures.
2534c582b7e3Smrg	 */
2535c582b7e3Smrg	if (info->textureSize < 512 * 1024) {
2536c582b7e3Smrg	    info->textureOffset = 0;
2537c582b7e3Smrg	    info->textureSize = 0;
2538c582b7e3Smrg	}
2539c582b7e3Smrg
2540c582b7e3Smrg	total = info->FbMapSize - info->textureSize;
2541c582b7e3Smrg	scanlines = total / width_bytes;
2542c582b7e3Smrg	if (scanlines > 8191) scanlines = 8191;
2543c582b7e3Smrg
2544c582b7e3Smrg	/* Recalculate the texture offset and size to accomodate any
2545c582b7e3Smrg	 * rounding to a whole number of scanlines.
2546c582b7e3Smrg	 */
2547c582b7e3Smrg	info->textureOffset = scanlines * width_bytes;
2548c582b7e3Smrg
2549c582b7e3Smrg	MemBox.x1 = 0;
2550c582b7e3Smrg	MemBox.y1 = 0;
2551c582b7e3Smrg	MemBox.x2 = pScrn->displayWidth;
2552c582b7e3Smrg	MemBox.y2 = scanlines;
2553c582b7e3Smrg
255484354367Smrg	if (!info->useEXA) {
255584354367Smrg	    if (!xf86InitFBManager(pScreen, &MemBox)) {
255684354367Smrg	        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
255784354367Smrg		           "Memory manager initialization to (%d,%d) (%d,%d) failed\n",
255884354367Smrg		           MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2);
255984354367Smrg	        return FALSE;
2560c582b7e3Smrg	    } else {
256184354367Smrg	        int width, height;
256284354367Smrg
256384354367Smrg	        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
256484354367Smrg		           "Memory manager initialized to (%d,%d) (%d,%d)\n",
256584354367Smrg		           MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2);
256684354367Smrg	        if ((fbarea = xf86AllocateOffscreenArea(pScreen,
256784354367Smrg						        pScrn->displayWidth,
256884354367Smrg						        2, 0, NULL, NULL, NULL))) {
256984354367Smrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
257084354367Smrg			       "Reserved area from (%d,%d) to (%d,%d)\n",
257184354367Smrg			       fbarea->box.x1, fbarea->box.y1,
257284354367Smrg			       fbarea->box.x2, fbarea->box.y2);
257384354367Smrg	        } else {
257484354367Smrg		    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to reserve area\n");
257584354367Smrg	        }
257684354367Smrg	        if (xf86QueryLargestOffscreenArea(pScreen, &width,
257784354367Smrg						  &height, 0, 0, 0)) {
257884354367Smrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
257984354367Smrg			       "Largest offscreen area available: %d x %d\n",
258084354367Smrg				width, height);
258184354367Smrg	        }
258284354367Smrg
258384354367Smrg		R128VerboseInitAccel(noAccel, pScreen);
2584c582b7e3Smrg	    }
2585c582b7e3Smrg	}
258684354367Smrg#ifdef USE_EXA
258784354367Smrg	else {
258884354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
258984354367Smrg		       "Filling in EXA memory info\n");
259084354367Smrg
259184354367Smrg	    R128VerboseInitAccel(noAccel, pScreen);
259284354367Smrg	    info->ExaDriver->offScreenBase = pScrn->virtualY * width_bytes;
259384354367Smrg
259484354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
259584354367Smrg		       "Filled in offs\n");
259684354367Smrg
259784354367Smrg	    /* Don't give EXA the true full memory size, because the
259884354367Smrg	       textureSize sized chunk on the end is handled by DRI */
259984354367Smrg	    info->ExaDriver->memorySize = total;
260084354367Smrg
260184354367Smrg	    R128VerboseInitEXA(pScreen);
260284354367Smrg	}
260384354367Smrg#endif
2604c582b7e3Smrg
2605c582b7e3Smrg				/* Allocate the shared back buffer */
260684354367Smrg	if(!info->useEXA) {
260784354367Smrg	    fbarea = xf86AllocateOffscreenArea(pScreen,
260884354367Smrg					       pScrn->virtualX,
260984354367Smrg					       pScrn->virtualY,
261084354367Smrg					       32, NULL, NULL, NULL);
261184354367Smrg
261284354367Smrg	    if (fbarea) {
261384354367Smrg		x1 = fbarea->box.x1;
261484354367Smrg		x2 = fbarea->box.x2;
261584354367Smrg		y1 = fbarea->box.y1;
261684354367Smrg		y2 = fbarea->box.y2;
261784354367Smrg	    }
261884354367Smrg	}
261984354367Smrg#ifdef USE_EXA
262084354367Smrg	else {
262184354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
262284354367Smrg		       "Actually trying an EXA allocation...\n");
262384354367Smrg	    osArea = exaOffscreenAlloc(pScreen,
262484354367Smrg				       pScrn->virtualY * width_bytes,
262584354367Smrg				       32, TRUE, NULL, NULL);
262684354367Smrg
262784354367Smrg	    if (osArea) {
262884354367Smrg		x1 = osArea->offset % width_bytes;
262984354367Smrg		x2 = (osArea->offset + osArea->size) % width_bytes;
263084354367Smrg		y1 = osArea->offset / width_bytes;
263184354367Smrg		y2 = (osArea->offset + osArea->size) / width_bytes;
263284354367Smrg
263384354367Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Went swimmingly...\n");
263484354367Smrg	    }
263584354367Smrg	}
263684354367Smrg#endif
263784354367Smrg
263884354367Smrg	if ((!info->useEXA && fbarea) || (info->useEXA && osArea)) {
263984354367Smrg	    /* info->backOffset = y1 * width_bytes + x1 * cpp; */
264084354367Smrg	    info->backOffset = R128_ALIGN(y1 * width_bytes + x1 * cpp, 16);
264184354367Smrg	    info->backX = info->backOffset % width_bytes;
264284354367Smrg	    info->backY = info->backOffset / width_bytes;
2643c582b7e3Smrg	    info->backPitch = pScrn->displayWidth;
264484354367Smrg
264584354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
264684354367Smrg		       "Reserved back buffer from (%d,%d) to (%d,%d) offset: %x\n",
264784354367Smrg		       x1, y1,
264884354367Smrg		       x2, y2, info->backOffset);
2649c582b7e3Smrg	} else {
265084354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to reserve back buffer\n");
2651c582b7e3Smrg	    info->backX = -1;
2652c582b7e3Smrg	    info->backY = -1;
2653c582b7e3Smrg	    info->backOffset = -1;
2654c582b7e3Smrg	    info->backPitch = -1;
2655c582b7e3Smrg	}
2656c582b7e3Smrg
2657c582b7e3Smrg				/* Allocate the shared depth buffer */
265884354367Smrg	if(!info->useEXA) {
265984354367Smrg	    fbarea = xf86AllocateOffscreenArea(pScreen,
266084354367Smrg					       pScrn->virtualX,
266184354367Smrg					       pScrn->virtualY + 1,
266284354367Smrg					       32, NULL, NULL, NULL);
266384354367Smrg	    if (fbarea) {
266484354367Smrg		x1 = fbarea->box.x1;
266584354367Smrg		x2 = fbarea->box.x2;
266684354367Smrg		y1 = fbarea->box.y1;
266784354367Smrg		y2 = fbarea->box.y2;
266884354367Smrg	    }
266984354367Smrg	}
267084354367Smrg#ifdef USE_EXA
267184354367Smrg	else {
267284354367Smrg	    osArea = exaOffscreenAlloc(pScreen,
267384354367Smrg				       (pScrn->virtualY + 1) * width_bytes,
267484354367Smrg				       32, TRUE, NULL, NULL);
267584354367Smrg
267684354367Smrg	    if (osArea) {
267784354367Smrg		x1 = osArea->offset % width_bytes;
267884354367Smrg		x2 = (osArea->offset + osArea->size) % width_bytes;
267984354367Smrg		y1 = osArea->offset / width_bytes;
268084354367Smrg		y2 = (osArea->offset + osArea->size) / width_bytes;
268184354367Smrg	    }
268284354367Smrg	}
268384354367Smrg#endif
268484354367Smrg
268584354367Smrg	if ((!info->useEXA && fbarea) || (info->useEXA && osArea)) {
268684354367Smrg	    /* info->depthOffset = y1 * width_bytes + x1 * cpp; */
268784354367Smrg	    info->depthOffset = R128_ALIGN(y1 * width_bytes + x1 * cpp, 16);
268884354367Smrg	    info->depthX = info->depthOffset % width_bytes;
268984354367Smrg	    info->depthY = info->depthOffset / width_bytes;
2690c582b7e3Smrg	    info->depthPitch = pScrn->displayWidth;
269184354367Smrg	    info->spanOffset = (y2 - 1) * width_bytes + x1 * cpp;
269284354367Smrg
269384354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
269484354367Smrg		       "Reserved depth buffer from (%d,%d) to (%d,%d) offset: %x\n",
269584354367Smrg		       x1, y1,
269684354367Smrg		       x2, y2, info->depthOffset);
269784354367Smrg
269884354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2699c582b7e3Smrg		       "Reserved depth span from (%d,%d) offset 0x%x\n",
270084354367Smrg		       x1, y2 - 1, info->spanOffset);
2701c582b7e3Smrg	} else {
270284354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to reserve depth buffer\n");
2703c582b7e3Smrg	    info->depthX = -1;
2704c582b7e3Smrg	    info->depthY = -1;
2705c582b7e3Smrg	    info->depthOffset = -1;
2706c582b7e3Smrg	    info->depthPitch = -1;
2707c582b7e3Smrg	    info->spanOffset = -1;
2708c582b7e3Smrg	}
2709c582b7e3Smrg
271084354367Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2711c582b7e3Smrg		   "Reserved %d kb for textures at offset 0x%x\n",
2712c582b7e3Smrg		   info->textureSize/1024, info->textureOffset);
2713c582b7e3Smrg    }
2714c582b7e3Smrg    else
271584354367Smrg#endif /* R128DRI */
2716c582b7e3Smrg    {
2717c582b7e3Smrg	MemBox.x1 = 0;
2718c582b7e3Smrg	MemBox.y1 = 0;
2719c582b7e3Smrg	MemBox.x2 = pScrn->displayWidth;
2720c582b7e3Smrg	y2        = (info->FbMapSize
2721c582b7e3Smrg		     / (pScrn->displayWidth *
2722c582b7e3Smrg			info->CurrentLayout.pixel_bytes));
2723c582b7e3Smrg				/* The acceleration engine uses 14 bit
2724c582b7e3Smrg				   signed coordinates, so we can't have any
2725c582b7e3Smrg				   drawable caches beyond this region. */
2726c582b7e3Smrg	if (y2 > 8191) y2 = 8191;
2727c582b7e3Smrg	MemBox.y2 = y2;
2728c582b7e3Smrg
272984354367Smrg	if (!info->useEXA) {
273084354367Smrg	    if (!xf86InitFBManager(pScreen, &MemBox)) {
273184354367Smrg	        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
273284354367Smrg		           "Memory manager initialization to (%d,%d) (%d,%d) failed\n",
273384354367Smrg		           MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2);
273484354367Smrg	        return FALSE;
2735c582b7e3Smrg	    } else {
273684354367Smrg	        int       width, height;
273784354367Smrg	        FBAreaPtr fbarea;
273884354367Smrg
273984354367Smrg	        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
274084354367Smrg		           "Memory manager initialized to (%d,%d) (%d,%d)\n",
274184354367Smrg		           MemBox.x1, MemBox.y1, MemBox.x2, MemBox.y2);
274284354367Smrg	        if ((fbarea = xf86AllocateOffscreenArea(pScreen, pScrn->displayWidth, 2, 0, NULL, NULL, NULL))) {
274384354367Smrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
274484354367Smrg			       "Reserved area from (%d,%d) to (%d,%d)\n",
274584354367Smrg			       fbarea->box.x1, fbarea->box.y1,
274684354367Smrg			       fbarea->box.x2, fbarea->box.y2);
274784354367Smrg	        } else {
274884354367Smrg		    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unable to reserve area\n");
274984354367Smrg	        }
275084354367Smrg	        if (xf86QueryLargestOffscreenArea(pScreen, &width, &height, 0, 0, 0)) {
275184354367Smrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
275284354367Smrg			       "Largest offscreen area available: %d x %d\n",
275384354367Smrg				width, height);
275484354367Smrg	        }
275584354367Smrg
275684354367Smrg		R128VerboseInitAccel(noAccel, pScreen);
2757c582b7e3Smrg	    }
2758c582b7e3Smrg	}
275984354367Smrg#ifdef USE_EXA
276084354367Smrg	else {
276184354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
276284354367Smrg		       "Filling in EXA memory info\n");
2763c582b7e3Smrg
276484354367Smrg	    R128VerboseInitAccel(noAccel, pScreen);
276584354367Smrg	    info->ExaDriver->offScreenBase = pScrn->virtualY * width_bytes;
276684354367Smrg
276784354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
276884354367Smrg		       "Filled in offs\n");
276984354367Smrg
277084354367Smrg	    info->ExaDriver->memorySize = info->FbMapSize;
277184354367Smrg	    R128VerboseInitEXA(pScreen);
2772c582b7e3Smrg	}
277384354367Smrg#endif
2774c582b7e3Smrg    }
2775c582b7e3Smrg
2776c582b7e3Smrg				/* DGA setup */
2777c582b7e3Smrg    R128DGAInit(pScreen);
2778c582b7e3Smrg
2779c582b7e3Smrg				/* Backing store setup */
2780c582b7e3Smrg    xf86SetBackingStore(pScreen);
2781c582b7e3Smrg
2782c582b7e3Smrg				/* Set Silken Mouse */
2783c582b7e3Smrg    xf86SetSilkenMouse(pScreen);
2784c582b7e3Smrg
2785c582b7e3Smrg				/* Cursor setup */
2786c582b7e3Smrg    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
2787c582b7e3Smrg
2788c582b7e3Smrg				/* Hardware cursor setup */
2789c582b7e3Smrg    if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) {
2790c582b7e3Smrg	if (R128CursorInit(pScreen)) {
2791c582b7e3Smrg	    int width, height;
2792c582b7e3Smrg
2793c582b7e3Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2794c582b7e3Smrg		       "Using hardware cursor (scanline %ld)\n",
2795c582b7e3Smrg		       info->cursor_start / pScrn->displayWidth);
2796c582b7e3Smrg	    if (xf86QueryLargestOffscreenArea(pScreen, &width, &height,
2797c582b7e3Smrg					      0, 0, 0)) {
279884354367Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2799c582b7e3Smrg			   "Largest offscreen area available: %d x %d\n",
2800c582b7e3Smrg			   width, height);
2801c582b7e3Smrg	    }
2802c582b7e3Smrg	} else {
280384354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2804c582b7e3Smrg		       "Hardware cursor initialization failed\n");
280584354367Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using software cursor\n");
2806c582b7e3Smrg	}
2807c582b7e3Smrg    } else {
2808c582b7e3Smrg	info->cursor_start = 0;
280984354367Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using software cursor\n");
2810c582b7e3Smrg    }
2811c582b7e3Smrg
2812c582b7e3Smrg				/* Colormap setup */
2813c582b7e3Smrg    if (!miCreateDefColormap(pScreen)) return FALSE;
2814c582b7e3Smrg    if (!xf86HandleColormaps(pScreen, 256, info->dac6bits ? 6 : 8,
281579e5230eSmacallan			     (
281679e5230eSmacallan#ifndef AVOID_FBDEV
281779e5230eSmacallan			     info->FBDev ? fbdevHWLoadPaletteWeak() :
281879e5230eSmacallan#endif
2819c582b7e3Smrg			     R128LoadPalette), NULL,
2820c582b7e3Smrg			     CMAP_PALETTED_TRUECOLOR
2821c582b7e3Smrg			     | CMAP_RELOAD_ON_MODE_SWITCH
2822c582b7e3Smrg#if 0 /* This option messes up text mode! (eich@suse.de) */
2823c582b7e3Smrg			     | CMAP_LOAD_EVEN_IF_OFFSCREEN
2824c582b7e3Smrg#endif
2825c582b7e3Smrg			     )) return FALSE;
2826c582b7e3Smrg
2827c582b7e3Smrg    /* DPMS setup - FIXME: also for mirror mode in non-fbdev case? - Michel */
282879e5230eSmacallan#ifndef AVOID_FBDEV
2829c582b7e3Smrg    if (info->FBDev)
2830c582b7e3Smrg	xf86DPMSInit(pScreen, fbdevHWDPMSSetWeak(), 0);
2831c582b7e3Smrg
283279e5230eSmacallan    else
283379e5230eSmacallan#endif
283479e5230eSmacallan    {
2835c582b7e3Smrg	if (info->DisplayType == MT_LCD)
2836c582b7e3Smrg	    xf86DPMSInit(pScreen, R128DisplayPowerManagementSetLCD, 0);
2837c582b7e3Smrg	else
2838c582b7e3Smrg	    xf86DPMSInit(pScreen, R128DisplayPowerManagementSet, 0);
2839c582b7e3Smrg    }
2840c582b7e3Smrg
2841c582b7e3Smrg    if (!info->IsSecondary)
2842c582b7e3Smrg	R128InitVideo(pScreen);
2843c582b7e3Smrg
2844c582b7e3Smrg				/* Provide SaveScreen */
2845c582b7e3Smrg    pScreen->SaveScreen  = R128SaveScreen;
2846c582b7e3Smrg
2847c582b7e3Smrg				/* Wrap CloseScreen */
2848c582b7e3Smrg    info->CloseScreen    = pScreen->CloseScreen;
2849c582b7e3Smrg    pScreen->CloseScreen = R128CloseScreen;
2850c582b7e3Smrg
2851c582b7e3Smrg				/* Note unused options */
2852c582b7e3Smrg    if (serverGeneration == 1)
2853c582b7e3Smrg	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
2854c582b7e3Smrg
285584354367Smrg#ifdef R128DRI
2856c582b7e3Smrg				/* DRI finalization */
2857c582b7e3Smrg    if (info->directRenderingEnabled) {
2858c582b7e3Smrg				/* Now that mi, fb, drm and others have
2859c582b7e3Smrg				   done their thing, complete the DRI
2860c582b7e3Smrg				   setup. */
2861c582b7e3Smrg	info->directRenderingEnabled = R128DRIFinishScreenInit(pScreen);
2862c582b7e3Smrg    }
2863c582b7e3Smrg    if (info->directRenderingEnabled) {
2864c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering enabled\n");
2865c582b7e3Smrg    } else {
2866c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2867c582b7e3Smrg		   "Direct rendering disabled\n");
2868c582b7e3Smrg    }
2869c582b7e3Smrg#endif
2870c582b7e3Smrg
2871c582b7e3Smrg    info->BlockHandler = pScreen->BlockHandler;
2872c582b7e3Smrg    pScreen->BlockHandler = R128BlockHandler;
2873c582b7e3Smrg
2874c582b7e3Smrg    return TRUE;
2875c582b7e3Smrg}
2876c582b7e3Smrg
2877c582b7e3Smrg/* Write common registers (initialized to 0). */
2878c582b7e3Smrgstatic void R128RestoreCommonRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
2879c582b7e3Smrg{
2880c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
2881c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
2882c582b7e3Smrg
2883c582b7e3Smrg    OUTREG(R128_FP_GEN_CNTL, restore->fp_gen_cntl | R128_FP_BLANK_DIS);
2884c582b7e3Smrg
2885c582b7e3Smrg    OUTREG(R128_OVR_CLR,              restore->ovr_clr);
2886c582b7e3Smrg    OUTREG(R128_OVR_WID_LEFT_RIGHT,   restore->ovr_wid_left_right);
2887c582b7e3Smrg    OUTREG(R128_OVR_WID_TOP_BOTTOM,   restore->ovr_wid_top_bottom);
2888c582b7e3Smrg    OUTREG(R128_OV0_SCALE_CNTL,       restore->ov0_scale_cntl);
2889c582b7e3Smrg    OUTREG(R128_MPP_TB_CONFIG,        restore->mpp_tb_config );
2890c582b7e3Smrg    OUTREG(R128_MPP_GP_CONFIG,        restore->mpp_gp_config );
2891c582b7e3Smrg    OUTREG(R128_SUBPIC_CNTL,          restore->subpic_cntl);
2892c582b7e3Smrg    OUTREG(R128_VIPH_CONTROL,         restore->viph_control);
2893c582b7e3Smrg    OUTREG(R128_I2C_CNTL_1,           restore->i2c_cntl_1);
2894c582b7e3Smrg    OUTREG(R128_GEN_INT_CNTL,         restore->gen_int_cntl);
2895c582b7e3Smrg    OUTREG(R128_CAP0_TRIG_CNTL,       restore->cap0_trig_cntl);
2896c582b7e3Smrg    OUTREG(R128_CAP1_TRIG_CNTL,       restore->cap1_trig_cntl);
2897c582b7e3Smrg    OUTREG(R128_BUS_CNTL,             restore->bus_cntl);
2898c582b7e3Smrg    OUTREG(R128_CONFIG_CNTL,          restore->config_cntl);
2899c582b7e3Smrg}
2900c582b7e3Smrg
2901c582b7e3Smrg/* Write CRTC registers. */
2902c582b7e3Smrgstatic void R128RestoreCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
2903c582b7e3Smrg{
2904c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
2905c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
2906c582b7e3Smrg
2907c582b7e3Smrg    OUTREG(R128_CRTC_GEN_CNTL,        restore->crtc_gen_cntl);
2908c582b7e3Smrg
2909c582b7e3Smrg    OUTREGP(R128_CRTC_EXT_CNTL, restore->crtc_ext_cntl,
2910c582b7e3Smrg	    R128_CRTC_VSYNC_DIS | R128_CRTC_HSYNC_DIS | R128_CRTC_DISPLAY_DIS);
2911c582b7e3Smrg
2912c582b7e3Smrg    OUTREGP(R128_DAC_CNTL, restore->dac_cntl,
2913c582b7e3Smrg	    R128_DAC_RANGE_CNTL | R128_DAC_BLANKING);
2914c582b7e3Smrg
2915c582b7e3Smrg    OUTREG(R128_CRTC_H_TOTAL_DISP,    restore->crtc_h_total_disp);
2916c582b7e3Smrg    OUTREG(R128_CRTC_H_SYNC_STRT_WID, restore->crtc_h_sync_strt_wid);
2917c582b7e3Smrg    OUTREG(R128_CRTC_V_TOTAL_DISP,    restore->crtc_v_total_disp);
2918c582b7e3Smrg    OUTREG(R128_CRTC_V_SYNC_STRT_WID, restore->crtc_v_sync_strt_wid);
2919c582b7e3Smrg    OUTREG(R128_CRTC_OFFSET,          restore->crtc_offset);
2920c582b7e3Smrg    OUTREG(R128_CRTC_OFFSET_CNTL,     restore->crtc_offset_cntl);
2921c582b7e3Smrg    OUTREG(R128_CRTC_PITCH,           restore->crtc_pitch);
2922c582b7e3Smrg}
2923c582b7e3Smrg
2924c582b7e3Smrg/* Write CRTC2 registers. */
2925c582b7e3Smrgstatic void R128RestoreCrtc2Registers(ScrnInfoPtr pScrn,
2926c582b7e3Smrg				       R128SavePtr restore)
2927c582b7e3Smrg{
2928c582b7e3Smrg    R128InfoPtr info        = R128PTR(pScrn);
2929c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
2930c582b7e3Smrg
2931c582b7e3Smrg    OUTREGP(R128_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl,
2932c582b7e3Smrg	    R128_CRTC2_DISP_DIS);
2933c582b7e3Smrg
2934c582b7e3Smrg    OUTREG(R128_CRTC2_H_TOTAL_DISP,    restore->crtc2_h_total_disp);
2935c582b7e3Smrg    OUTREG(R128_CRTC2_H_SYNC_STRT_WID, restore->crtc2_h_sync_strt_wid);
2936c582b7e3Smrg    OUTREG(R128_CRTC2_V_TOTAL_DISP,    restore->crtc2_v_total_disp);
2937c582b7e3Smrg    OUTREG(R128_CRTC2_V_SYNC_STRT_WID, restore->crtc2_v_sync_strt_wid);
2938c582b7e3Smrg    OUTREG(R128_CRTC2_OFFSET,          restore->crtc2_offset);
2939c582b7e3Smrg    OUTREG(R128_CRTC2_OFFSET_CNTL,     restore->crtc2_offset_cntl);
2940c582b7e3Smrg    OUTREG(R128_CRTC2_PITCH,           restore->crtc2_pitch);
2941c582b7e3Smrg}
2942c582b7e3Smrg
2943c582b7e3Smrg/* Write flat panel registers */
2944c582b7e3Smrgstatic void R128RestoreFPRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
2945c582b7e3Smrg{
2946c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
2947c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
2948c582b7e3Smrg    CARD32        tmp;
2949c582b7e3Smrg
2950c582b7e3Smrg    if (info->BIOSDisplay != R128_DUALHEAD)
2951c582b7e3Smrg        OUTREG(R128_CRTC2_GEN_CNTL,       restore->crtc2_gen_cntl);
2952c582b7e3Smrg    OUTREG(R128_FP_HORZ_STRETCH,      restore->fp_horz_stretch);
2953c582b7e3Smrg    OUTREG(R128_FP_VERT_STRETCH,      restore->fp_vert_stretch);
2954c582b7e3Smrg    OUTREG(R128_FP_CRTC_H_TOTAL_DISP, restore->fp_crtc_h_total_disp);
2955c582b7e3Smrg    OUTREG(R128_FP_CRTC_V_TOTAL_DISP, restore->fp_crtc_v_total_disp);
2956c582b7e3Smrg    OUTREG(R128_FP_H_SYNC_STRT_WID,   restore->fp_h_sync_strt_wid);
2957c582b7e3Smrg    OUTREG(R128_FP_V_SYNC_STRT_WID,   restore->fp_v_sync_strt_wid);
2958c582b7e3Smrg    OUTREG(R128_TMDS_CRC,             restore->tmds_crc);
2959c582b7e3Smrg    OUTREG(R128_FP_PANEL_CNTL,        restore->fp_panel_cntl);
2960c582b7e3Smrg    OUTREG(R128_FP_GEN_CNTL, restore->fp_gen_cntl & ~(CARD32)R128_FP_BLANK_DIS);
2961c582b7e3Smrg
2962c582b7e3Smrg    if(info->isDFP) return;
2963c582b7e3Smrg
2964c582b7e3Smrg    tmp = INREG(R128_LVDS_GEN_CNTL);
2965c582b7e3Smrg    if ((tmp & (R128_LVDS_ON | R128_LVDS_BLON)) ==
2966c582b7e3Smrg	(restore->lvds_gen_cntl & (R128_LVDS_ON | R128_LVDS_BLON))) {
2967c582b7e3Smrg	OUTREG(R128_LVDS_GEN_CNTL, restore->lvds_gen_cntl);
2968c582b7e3Smrg    } else {
2969c582b7e3Smrg	if (restore->lvds_gen_cntl & (R128_LVDS_ON | R128_LVDS_BLON)) {
2970c582b7e3Smrg	    OUTREG(R128_LVDS_GEN_CNTL,
2971c582b7e3Smrg		   restore->lvds_gen_cntl & (CARD32)~R128_LVDS_BLON);
2972c582b7e3Smrg	    usleep(R128PTR(pScrn)->PanelPwrDly * 1000);
2973c582b7e3Smrg	    OUTREG(R128_LVDS_GEN_CNTL, restore->lvds_gen_cntl);
2974c582b7e3Smrg	} else {
2975c582b7e3Smrg	    OUTREG(R128_LVDS_GEN_CNTL, restore->lvds_gen_cntl | R128_LVDS_BLON);
2976c582b7e3Smrg	    usleep(R128PTR(pScrn)->PanelPwrDly * 1000);
2977c582b7e3Smrg	    OUTREG(R128_LVDS_GEN_CNTL, restore->lvds_gen_cntl);
2978c582b7e3Smrg	}
2979c582b7e3Smrg    }
2980c582b7e3Smrg}
2981c582b7e3Smrg
2982c582b7e3Smrgstatic void R128PLLWaitForReadUpdateComplete(ScrnInfoPtr pScrn)
2983c582b7e3Smrg{
2984c582b7e3Smrg    while (INPLL(pScrn, R128_PPLL_REF_DIV) & R128_PPLL_ATOMIC_UPDATE_R);
2985c582b7e3Smrg}
2986c582b7e3Smrg
2987c582b7e3Smrgstatic void R128PLLWriteUpdate(ScrnInfoPtr pScrn)
2988c582b7e3Smrg{
2989c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
2990c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
2991c582b7e3Smrg
2992c582b7e3Smrg    while (INPLL(pScrn, R128_PPLL_REF_DIV) & R128_PPLL_ATOMIC_UPDATE_R);
2993c582b7e3Smrg
2994c582b7e3Smrg    OUTPLLP(pScrn, R128_PPLL_REF_DIV, R128_PPLL_ATOMIC_UPDATE_W,
2995c582b7e3Smrg	    ~R128_PPLL_ATOMIC_UPDATE_W);
2996c582b7e3Smrg
2997c582b7e3Smrg}
2998c582b7e3Smrg
2999c582b7e3Smrgstatic void R128PLL2WaitForReadUpdateComplete(ScrnInfoPtr pScrn)
3000c582b7e3Smrg{
3001c582b7e3Smrg    while (INPLL(pScrn, R128_P2PLL_REF_DIV) & R128_P2PLL_ATOMIC_UPDATE_R);
3002c582b7e3Smrg}
3003c582b7e3Smrg
3004c582b7e3Smrgstatic void R128PLL2WriteUpdate(ScrnInfoPtr pScrn)
3005c582b7e3Smrg{
3006c582b7e3Smrg    R128InfoPtr  info       = R128PTR(pScrn);
3007c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
3008c582b7e3Smrg
3009c582b7e3Smrg    while (INPLL(pScrn, R128_P2PLL_REF_DIV) & R128_P2PLL_ATOMIC_UPDATE_R);
3010c582b7e3Smrg
3011c582b7e3Smrg    OUTPLLP(pScrn, R128_P2PLL_REF_DIV,
3012c582b7e3Smrg	    R128_P2PLL_ATOMIC_UPDATE_W,
3013c582b7e3Smrg	    ~(R128_P2PLL_ATOMIC_UPDATE_W));
3014c582b7e3Smrg}
3015c582b7e3Smrg
3016c582b7e3Smrg/* Write PLL registers. */
3017c582b7e3Smrgstatic void R128RestorePLLRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
3018c582b7e3Smrg{
3019c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
3020c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
3021c582b7e3Smrg
3022c582b7e3Smrg
3023c582b7e3Smrg    OUTPLLP(pScrn, R128_VCLK_ECP_CNTL,
3024c582b7e3Smrg	    R128_VCLK_SRC_SEL_CPUCLK,
3025c582b7e3Smrg	    ~(R128_VCLK_SRC_SEL_MASK));
3026c582b7e3Smrg
3027c582b7e3Smrg    OUTPLLP(pScrn,
3028c582b7e3Smrg	    R128_PPLL_CNTL,
3029c582b7e3Smrg	    R128_PPLL_RESET
3030c582b7e3Smrg	    | R128_PPLL_ATOMIC_UPDATE_EN
3031c582b7e3Smrg	    | R128_PPLL_VGA_ATOMIC_UPDATE_EN,
3032c582b7e3Smrg	    ~(R128_PPLL_RESET
3033c582b7e3Smrg	      | R128_PPLL_ATOMIC_UPDATE_EN
3034c582b7e3Smrg	      | R128_PPLL_VGA_ATOMIC_UPDATE_EN));
3035c582b7e3Smrg
3036c582b7e3Smrg    OUTREGP(R128_CLOCK_CNTL_INDEX, R128_PLL_DIV_SEL, ~(R128_PLL_DIV_SEL));
3037c582b7e3Smrg
3038c582b7e3Smrg/*        R128PLLWaitForReadUpdateComplete(pScrn);*/
3039c582b7e3Smrg    OUTPLLP(pScrn, R128_PPLL_REF_DIV,
3040c582b7e3Smrg	    restore->ppll_ref_div, ~R128_PPLL_REF_DIV_MASK);
3041c582b7e3Smrg/*        R128PLLWriteUpdate(pScrn);
3042c582b7e3Smrg
3043c582b7e3Smrg        R128PLLWaitForReadUpdateComplete(pScrn);*/
3044c582b7e3Smrg    OUTPLLP(pScrn, R128_PPLL_DIV_3,
3045c582b7e3Smrg	    restore->ppll_div_3, ~R128_PPLL_FB3_DIV_MASK);
3046c582b7e3Smrg/*    R128PLLWriteUpdate(pScrn);*/
3047c582b7e3Smrg    OUTPLLP(pScrn, R128_PPLL_DIV_3,
3048c582b7e3Smrg	    restore->ppll_div_3, ~R128_PPLL_POST3_DIV_MASK);
3049c582b7e3Smrg
3050c582b7e3Smrg    R128PLLWriteUpdate(pScrn);
3051c582b7e3Smrg    R128PLLWaitForReadUpdateComplete(pScrn);
3052c582b7e3Smrg
30539e881af1Smacallan    OUTPLLP(pScrn, R128_PPLL_DIV_0,
30549e881af1Smacallan	    restore->ppll_div_0, ~R128_PPLL_FB0_DIV_MASK);
30559e881af1Smacallan/*    R128PLLWriteUpdate(pScrn);*/
30569e881af1Smacallan    OUTPLLP(pScrn, R128_PPLL_DIV_0,
30579e881af1Smacallan	    restore->ppll_div_0, ~R128_PPLL_POST0_DIV_MASK);
30589e881af1Smacallan
30599e881af1Smacallan    R128PLLWriteUpdate(pScrn);
30609e881af1Smacallan    R128PLLWaitForReadUpdateComplete(pScrn);
30619e881af1Smacallan
3062c582b7e3Smrg    OUTPLL(R128_HTOTAL_CNTL, restore->htotal_cntl);
3063c582b7e3Smrg/*    R128PLLWriteUpdate(pScrn);*/
3064c582b7e3Smrg
3065c582b7e3Smrg    OUTPLLP(pScrn, R128_PPLL_CNTL, 0, ~(R128_PPLL_RESET
3066c582b7e3Smrg					| R128_PPLL_SLEEP
3067c582b7e3Smrg					| R128_PPLL_ATOMIC_UPDATE_EN
3068c582b7e3Smrg					| R128_PPLL_VGA_ATOMIC_UPDATE_EN));
3069c582b7e3Smrg
3070c582b7e3Smrg    R128TRACE(("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
3071c582b7e3Smrg	       restore->ppll_ref_div,
3072c582b7e3Smrg	       restore->ppll_div_3,
3073c582b7e3Smrg	       restore->htotal_cntl,
3074c582b7e3Smrg	       INPLL(pScrn, R128_PPLL_CNTL)));
3075c582b7e3Smrg    R128TRACE(("Wrote: rd=%d, fd=%d, pd=%d\n",
3076c582b7e3Smrg	       restore->ppll_ref_div & R128_PPLL_REF_DIV_MASK,
3077c582b7e3Smrg	       restore->ppll_div_3 & R128_PPLL_FB3_DIV_MASK,
3078c582b7e3Smrg	       (restore->ppll_div_3 & R128_PPLL_POST3_DIV_MASK) >> 16));
3079c582b7e3Smrg
3080c582b7e3Smrg    usleep(5000); /* let the clock lock */
3081c582b7e3Smrg
3082c582b7e3Smrg    OUTPLLP(pScrn, R128_VCLK_ECP_CNTL,
3083c582b7e3Smrg	    R128_VCLK_SRC_SEL_PPLLCLK,
3084c582b7e3Smrg	    ~(R128_VCLK_SRC_SEL_MASK));
3085c582b7e3Smrg
3086c582b7e3Smrg}
3087c582b7e3Smrg
3088c582b7e3Smrg/* Write PLL2 registers. */
3089c582b7e3Smrgstatic void R128RestorePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
3090c582b7e3Smrg{
3091c582b7e3Smrg    R128InfoPtr info        = R128PTR(pScrn);
3092c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
3093c582b7e3Smrg
3094c582b7e3Smrg    OUTPLLP(pScrn, R128_V2CLK_VCLKTV_CNTL,
3095c582b7e3Smrg	    R128_V2CLK_SRC_SEL_CPUCLK,
3096c582b7e3Smrg	    ~R128_V2CLK_SRC_SEL_MASK);
3097c582b7e3Smrg
3098c582b7e3Smrg    OUTPLLP(pScrn,
3099c582b7e3Smrg	    R128_P2PLL_CNTL,
3100c582b7e3Smrg	    R128_P2PLL_RESET
3101c582b7e3Smrg	    | R128_P2PLL_ATOMIC_UPDATE_EN
3102c582b7e3Smrg	    | R128_P2PLL_VGA_ATOMIC_UPDATE_EN,
3103c582b7e3Smrg	    ~(R128_P2PLL_RESET
3104c582b7e3Smrg	      | R128_P2PLL_ATOMIC_UPDATE_EN
3105c582b7e3Smrg	      | R128_P2PLL_VGA_ATOMIC_UPDATE_EN));
3106c582b7e3Smrg
3107c582b7e3Smrg#if 1
3108c582b7e3Smrg    OUTREGP(R128_CLOCK_CNTL_INDEX, 0, R128_PLL2_DIV_SEL_MASK);
3109c582b7e3Smrg#endif
3110c582b7e3Smrg
3111c582b7e3Smrg        /*R128PLL2WaitForReadUpdateComplete(pScrn);*/
3112c582b7e3Smrg
3113c582b7e3Smrg    OUTPLLP(pScrn, R128_P2PLL_REF_DIV, restore->p2pll_ref_div, ~R128_P2PLL_REF_DIV_MASK);
3114c582b7e3Smrg
3115c582b7e3Smrg/*        R128PLL2WriteUpdate(pScrn);
3116c582b7e3Smrg    R128PLL2WaitForReadUpdateComplete(pScrn);*/
3117c582b7e3Smrg
3118c582b7e3Smrg    OUTPLLP(pScrn, R128_P2PLL_DIV_0,
3119c582b7e3Smrg			restore->p2pll_div_0, ~R128_P2PLL_FB0_DIV_MASK);
3120c582b7e3Smrg
3121c582b7e3Smrg/*    R128PLL2WriteUpdate(pScrn);
3122c582b7e3Smrg    R128PLL2WaitForReadUpdateComplete(pScrn);*/
3123c582b7e3Smrg
3124c582b7e3Smrg    OUTPLLP(pScrn, R128_P2PLL_DIV_0,
3125c582b7e3Smrg			restore->p2pll_div_0, ~R128_P2PLL_POST0_DIV_MASK);
3126c582b7e3Smrg
3127c582b7e3Smrg    R128PLL2WriteUpdate(pScrn);
3128c582b7e3Smrg    R128PLL2WaitForReadUpdateComplete(pScrn);
3129c582b7e3Smrg
3130c582b7e3Smrg    OUTPLL(R128_HTOTAL2_CNTL, restore->htotal_cntl2);
3131c582b7e3Smrg
3132c582b7e3Smrg/*        R128PLL2WriteUpdate(pScrn);*/
3133c582b7e3Smrg
3134c582b7e3Smrg    OUTPLLP(pScrn, R128_P2PLL_CNTL, 0, ~(R128_P2PLL_RESET
3135c582b7e3Smrg					| R128_P2PLL_SLEEP
3136c582b7e3Smrg					| R128_P2PLL_ATOMIC_UPDATE_EN
3137c582b7e3Smrg					| R128_P2PLL_VGA_ATOMIC_UPDATE_EN));
3138c582b7e3Smrg
3139c582b7e3Smrg    R128TRACE(("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
3140c582b7e3Smrg	       restore->p2pll_ref_div,
3141c582b7e3Smrg	       restore->p2pll_div_0,
3142c582b7e3Smrg	       restore->htotal_cntl2,
31439e881af1Smacallan	       INPLL(pScrn, R128_P2PLL_CNTL)));
314484354367Smrg    R128TRACE(("Wrote: rd=%d, fd=%d, pd=%d\n",
314584354367Smrg	       restore->p2pll_ref_div & R128_P2PLL_REF_DIV_MASK,
314684354367Smrg	       restore->p2pll_div_0 & R128_P2PLL_FB0_DIV_MASK,
314784354367Smrg	       (restore->p2pll_div_0 & R128_P2PLL_POST0_DIV_MASK) >>16));
3148c582b7e3Smrg
3149c582b7e3Smrg    usleep(5000); /* Let the clock to lock */
3150c582b7e3Smrg
3151c582b7e3Smrg    OUTPLLP(pScrn, R128_V2CLK_VCLKTV_CNTL,
3152c582b7e3Smrg	    R128_V2CLK_SRC_SEL_P2PLLCLK,
3153c582b7e3Smrg	    ~R128_V2CLK_SRC_SEL_MASK);
3154c582b7e3Smrg
3155c582b7e3Smrg}
3156c582b7e3Smrg
3157c582b7e3Smrg/* Write DDA registers. */
3158c582b7e3Smrgstatic void R128RestoreDDARegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
3159c582b7e3Smrg{
3160c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
3161c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
3162c582b7e3Smrg
3163c582b7e3Smrg    OUTREG(R128_DDA_CONFIG, restore->dda_config);
3164c582b7e3Smrg    OUTREG(R128_DDA_ON_OFF, restore->dda_on_off);
3165c582b7e3Smrg}
3166c582b7e3Smrg
3167c582b7e3Smrg/* Write DDA registers. */
3168c582b7e3Smrgstatic void R128RestoreDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
3169c582b7e3Smrg{
3170c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
3171c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
3172c582b7e3Smrg
3173c582b7e3Smrg    OUTREG(R128_DDA2_CONFIG, restore->dda2_config);
3174c582b7e3Smrg    OUTREG(R128_DDA2_ON_OFF, restore->dda2_on_off);
3175c582b7e3Smrg}
3176c582b7e3Smrg
3177c582b7e3Smrg/* Write palette data. */
3178c582b7e3Smrgstatic void R128RestorePalette(ScrnInfoPtr pScrn, R128SavePtr restore)
3179c582b7e3Smrg{
3180c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
3181c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
3182c582b7e3Smrg    int           i;
3183c582b7e3Smrg
3184c582b7e3Smrg    if (!restore->palette_valid) return;
3185c582b7e3Smrg
3186c582b7e3Smrg    PAL_SELECT(1);
3187c582b7e3Smrg    OUTPAL_START(0);
3188c582b7e3Smrg    for (i = 0; i < 256; i++) {
3189c582b7e3Smrg	R128WaitForFifo(pScrn, 32); /* delay */
3190c582b7e3Smrg	OUTPAL_NEXT_CARD32(restore->palette2[i]);
3191c582b7e3Smrg    }
3192c582b7e3Smrg
3193c582b7e3Smrg    PAL_SELECT(0);
3194c582b7e3Smrg    OUTPAL_START(0);
3195c582b7e3Smrg    for (i = 0; i < 256; i++) {
3196c582b7e3Smrg	R128WaitForFifo(pScrn, 32); /* delay */
3197c582b7e3Smrg	OUTPAL_NEXT_CARD32(restore->palette[i]);
3198c582b7e3Smrg    }
3199c582b7e3Smrg
3200c582b7e3Smrg}
3201c582b7e3Smrg
3202c582b7e3Smrg/* Write out state to define a new video mode.  */
3203c582b7e3Smrgstatic void R128RestoreMode(ScrnInfoPtr pScrn, R128SavePtr restore)
3204c582b7e3Smrg{
3205c582b7e3Smrg    R128InfoPtr info = R128PTR(pScrn);
3206c582b7e3Smrg    DevUnion* pPriv;
3207c582b7e3Smrg    R128EntPtr pR128Ent;
3208c582b7e3Smrg    static R128SaveRec restore0;
3209c582b7e3Smrg
3210c582b7e3Smrg    R128TRACE(("R128RestoreMode(%p)\n", restore));
3211c582b7e3Smrg    if(!info->HasCRTC2)
3212c582b7e3Smrg    {
3213c582b7e3Smrg    	R128RestoreCommonRegisters(pScrn, restore);
3214c582b7e3Smrg        R128RestoreDDARegisters(pScrn, restore);
3215c582b7e3Smrg    	R128RestoreCrtcRegisters(pScrn, restore);
3216c582b7e3Smrg        if((info->DisplayType == MT_DFP) ||
3217c582b7e3Smrg           (info->DisplayType == MT_LCD))
3218c582b7e3Smrg        {
3219c582b7e3Smrg	    R128RestoreFPRegisters(pScrn, restore);
3220c582b7e3Smrg        }
3221c582b7e3Smrg        R128RestorePLLRegisters(pScrn, restore);
3222c582b7e3Smrg        return;
3223c582b7e3Smrg    }
3224c582b7e3Smrg
3225c582b7e3Smrg    pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
3226c582b7e3Smrg                   getR128EntityIndex());
3227c582b7e3Smrg    pR128Ent = pPriv->ptr;
3228c582b7e3Smrg
3229c582b7e3Smrg
3230c582b7e3Smrg    /*****
3231c582b7e3Smrg      When changing mode with Dual-head card (VE/M6), care must
3232c582b7e3Smrg      be taken for the special order in setting registers. CRTC2 has
3233c582b7e3Smrg      to be set before changing CRTC_EXT register.
3234c582b7e3Smrg      In the dual-head setup, X server calls this routine twice with
3235c582b7e3Smrg      primary and secondary pScrn pointers respectively. The calls
3236c582b7e3Smrg      can come with different order. Regardless the order of X server issuing
3237c582b7e3Smrg      the calls, we have to ensure we set registers in the right order!!!
3238c582b7e3Smrg      Otherwise we may get a blank screen.
3239c582b7e3Smrg    *****/
3240c582b7e3Smrg
3241c582b7e3Smrg    if(info->IsSecondary)
3242c582b7e3Smrg    {
3243c582b7e3Smrg	if (!pR128Ent->RestorePrimary  && !info->SwitchingMode)
3244c582b7e3Smrg	    R128RestoreCommonRegisters(pScrn, restore);
3245c582b7e3Smrg        R128RestoreDDA2Registers(pScrn, restore);
3246c582b7e3Smrg        R128RestoreCrtc2Registers(pScrn, restore);
3247c582b7e3Smrg        R128RestorePLL2Registers(pScrn, restore);
3248c582b7e3Smrg
3249c582b7e3Smrg	if(info->SwitchingMode) return;
3250c582b7e3Smrg
3251c582b7e3Smrg        pR128Ent->IsSecondaryRestored = TRUE;
3252c582b7e3Smrg
3253c582b7e3Smrg        if(pR128Ent->RestorePrimary)
3254c582b7e3Smrg        {
3255c582b7e3Smrg            R128InfoPtr info0 = R128PTR(pR128Ent->pPrimaryScrn);
3256c582b7e3Smrg            pR128Ent->RestorePrimary = FALSE;
3257c582b7e3Smrg
3258c582b7e3Smrg            R128RestoreCrtcRegisters(pScrn, &restore0);
3259c582b7e3Smrg            if((info0->DisplayType == MT_DFP) ||
3260c582b7e3Smrg               (info0->DisplayType == MT_LCD))
3261c582b7e3Smrg            {
3262c582b7e3Smrg                R128RestoreFPRegisters(pScrn, &restore0);
3263c582b7e3Smrg            }
3264c582b7e3Smrg
3265c582b7e3Smrg            R128RestorePLLRegisters(pScrn, &restore0);
3266c582b7e3Smrg            pR128Ent->IsSecondaryRestored = FALSE;
3267c582b7e3Smrg
3268c582b7e3Smrg        }
3269c582b7e3Smrg    }
3270c582b7e3Smrg    else
3271c582b7e3Smrg    {
3272c582b7e3Smrg	if (!pR128Ent->IsSecondaryRestored)
3273c582b7e3Smrg            R128RestoreCommonRegisters(pScrn, restore);
3274c582b7e3Smrg        R128RestoreDDARegisters(pScrn, restore);
3275c582b7e3Smrg        if(!pR128Ent->HasSecondary || pR128Ent->IsSecondaryRestored
3276c582b7e3Smrg            || info->SwitchingMode)
3277c582b7e3Smrg        {
3278c582b7e3Smrg	    pR128Ent->IsSecondaryRestored = FALSE;
3279c582b7e3Smrg            R128RestoreCrtcRegisters(pScrn, restore);
3280c582b7e3Smrg            if((info->DisplayType == MT_DFP) ||
3281c582b7e3Smrg               (info->DisplayType == MT_LCD))
3282c582b7e3Smrg            {
3283c582b7e3Smrg               R128RestoreFPRegisters(pScrn, restore);
3284c582b7e3Smrg            }
3285c582b7e3Smrg            R128RestorePLLRegisters(pScrn, restore);
3286c582b7e3Smrg        }
3287c582b7e3Smrg        else
3288c582b7e3Smrg        {
3289c582b7e3Smrg            memcpy(&restore0, restore, sizeof(restore0));
3290c582b7e3Smrg            pR128Ent->RestorePrimary = TRUE;
3291c582b7e3Smrg        }
3292c582b7e3Smrg    }
3293c582b7e3Smrg
3294c582b7e3Smrg    R128RestorePalette(pScrn, restore);
3295c582b7e3Smrg}
3296c582b7e3Smrg
3297c582b7e3Smrg/* Read common registers. */
3298c582b7e3Smrgstatic void R128SaveCommonRegisters(ScrnInfoPtr pScrn, R128SavePtr save)
3299c582b7e3Smrg{
3300c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
3301c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
3302c582b7e3Smrg
3303c582b7e3Smrg    save->ovr_clr            = INREG(R128_OVR_CLR);
3304c582b7e3Smrg    save->ovr_wid_left_right = INREG(R128_OVR_WID_LEFT_RIGHT);
3305c582b7e3Smrg    save->ovr_wid_top_bottom = INREG(R128_OVR_WID_TOP_BOTTOM);
3306c582b7e3Smrg    save->ov0_scale_cntl     = INREG(R128_OV0_SCALE_CNTL);
3307c582b7e3Smrg    save->mpp_tb_config      = INREG(R128_MPP_TB_CONFIG);
3308c582b7e3Smrg    save->mpp_gp_config      = INREG(R128_MPP_GP_CONFIG);
3309c582b7e3Smrg    save->subpic_cntl        = INREG(R128_SUBPIC_CNTL);
3310c582b7e3Smrg    save->viph_control       = INREG(R128_VIPH_CONTROL);
3311c582b7e3Smrg    save->i2c_cntl_1         = INREG(R128_I2C_CNTL_1);
3312c582b7e3Smrg    save->gen_int_cntl       = INREG(R128_GEN_INT_CNTL);
3313c582b7e3Smrg    save->cap0_trig_cntl     = INREG(R128_CAP0_TRIG_CNTL);
3314c582b7e3Smrg    save->cap1_trig_cntl     = INREG(R128_CAP1_TRIG_CNTL);
3315c582b7e3Smrg    save->bus_cntl           = INREG(R128_BUS_CNTL);
3316c582b7e3Smrg    save->config_cntl        = INREG(R128_CONFIG_CNTL);
3317c582b7e3Smrg}
3318c582b7e3Smrg
3319c582b7e3Smrg/* Read CRTC registers. */
3320c582b7e3Smrgstatic void R128SaveCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr save)
3321c582b7e3Smrg{
3322c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
3323c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
3324c582b7e3Smrg
3325c582b7e3Smrg    save->crtc_gen_cntl        = INREG(R128_CRTC_GEN_CNTL);
3326c582b7e3Smrg    save->crtc_ext_cntl        = INREG(R128_CRTC_EXT_CNTL);
3327c582b7e3Smrg    save->dac_cntl             = INREG(R128_DAC_CNTL);
3328c582b7e3Smrg    save->crtc_h_total_disp    = INREG(R128_CRTC_H_TOTAL_DISP);
3329c582b7e3Smrg    save->crtc_h_sync_strt_wid = INREG(R128_CRTC_H_SYNC_STRT_WID);
3330c582b7e3Smrg    save->crtc_v_total_disp    = INREG(R128_CRTC_V_TOTAL_DISP);
3331c582b7e3Smrg    save->crtc_v_sync_strt_wid = INREG(R128_CRTC_V_SYNC_STRT_WID);
3332c582b7e3Smrg    save->crtc_offset          = INREG(R128_CRTC_OFFSET);
3333c582b7e3Smrg    save->crtc_offset_cntl     = INREG(R128_CRTC_OFFSET_CNTL);
3334c582b7e3Smrg    save->crtc_pitch           = INREG(R128_CRTC_PITCH);
3335c582b7e3Smrg}
3336c582b7e3Smrg
3337c582b7e3Smrg/* Read flat panel registers */
3338c582b7e3Smrgstatic void R128SaveFPRegisters(ScrnInfoPtr pScrn, R128SavePtr save)
3339c582b7e3Smrg{
3340c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
3341c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
3342c582b7e3Smrg
3343c582b7e3Smrg    if (info->BIOSDisplay != R128_DUALHEAD)
3344c582b7e3Smrg        save->crtc2_gen_cntl       = INREG(R128_CRTC2_GEN_CNTL);
3345c582b7e3Smrg    save->fp_crtc_h_total_disp = INREG(R128_FP_CRTC_H_TOTAL_DISP);
3346c582b7e3Smrg    save->fp_crtc_v_total_disp = INREG(R128_FP_CRTC_V_TOTAL_DISP);
3347c582b7e3Smrg    save->fp_gen_cntl          = INREG(R128_FP_GEN_CNTL);
3348c582b7e3Smrg    save->fp_h_sync_strt_wid   = INREG(R128_FP_H_SYNC_STRT_WID);
3349c582b7e3Smrg    save->fp_horz_stretch      = INREG(R128_FP_HORZ_STRETCH);
3350c582b7e3Smrg    save->fp_panel_cntl        = INREG(R128_FP_PANEL_CNTL);
3351c582b7e3Smrg    save->fp_v_sync_strt_wid   = INREG(R128_FP_V_SYNC_STRT_WID);
3352c582b7e3Smrg    save->fp_vert_stretch      = INREG(R128_FP_VERT_STRETCH);
3353c582b7e3Smrg    save->lvds_gen_cntl        = INREG(R128_LVDS_GEN_CNTL);
3354c582b7e3Smrg    save->tmds_crc             = INREG(R128_TMDS_CRC);
3355c582b7e3Smrg    save->tmds_transmitter_cntl = INREG(R128_TMDS_TRANSMITTER_CNTL);
3356c582b7e3Smrg}
3357c582b7e3Smrg
3358c582b7e3Smrg/* Read CRTC2 registers. */
3359c582b7e3Smrgstatic void R128SaveCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save)
3360c582b7e3Smrg{
3361c582b7e3Smrg    R128InfoPtr info        = R128PTR(pScrn);
3362c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
3363c582b7e3Smrg
3364c582b7e3Smrg    save->crtc2_gen_cntl        = INREG(R128_CRTC2_GEN_CNTL);
3365c582b7e3Smrg    save->crtc2_h_total_disp    = INREG(R128_CRTC2_H_TOTAL_DISP);
3366c582b7e3Smrg    save->crtc2_h_sync_strt_wid = INREG(R128_CRTC2_H_SYNC_STRT_WID);
3367c582b7e3Smrg    save->crtc2_v_total_disp    = INREG(R128_CRTC2_V_TOTAL_DISP);
3368c582b7e3Smrg    save->crtc2_v_sync_strt_wid = INREG(R128_CRTC2_V_SYNC_STRT_WID);
3369c582b7e3Smrg    save->crtc2_offset          = INREG(R128_CRTC2_OFFSET);
3370c582b7e3Smrg    save->crtc2_offset_cntl     = INREG(R128_CRTC2_OFFSET_CNTL);
3371c582b7e3Smrg    save->crtc2_pitch           = INREG(R128_CRTC2_PITCH);
3372c582b7e3Smrg}
3373c582b7e3Smrg
3374c582b7e3Smrg/* Read PLL registers. */
3375c582b7e3Smrgstatic void R128SavePLLRegisters(ScrnInfoPtr pScrn, R128SavePtr save)
3376c582b7e3Smrg{
3377c582b7e3Smrg    save->ppll_ref_div         = INPLL(pScrn, R128_PPLL_REF_DIV);
3378c582b7e3Smrg    save->ppll_div_3           = INPLL(pScrn, R128_PPLL_DIV_3);
33799e881af1Smacallan    save->ppll_div_0           = INPLL(pScrn, R128_PPLL_DIV_0);
3380c582b7e3Smrg    save->htotal_cntl          = INPLL(pScrn, R128_HTOTAL_CNTL);
3381c582b7e3Smrg
3382c582b7e3Smrg    R128TRACE(("Read: 0x%08x 0x%08x 0x%08x\n",
3383c582b7e3Smrg	       save->ppll_ref_div,
3384c582b7e3Smrg	       save->ppll_div_3,
3385c582b7e3Smrg	       save->htotal_cntl));
3386c582b7e3Smrg    R128TRACE(("Read: rd=%d, fd=%d, pd=%d\n",
3387c582b7e3Smrg	       save->ppll_ref_div & R128_PPLL_REF_DIV_MASK,
3388c582b7e3Smrg	       save->ppll_div_3 & R128_PPLL_FB3_DIV_MASK,
3389c582b7e3Smrg	       (save->ppll_div_3 & R128_PPLL_POST3_DIV_MASK) >> 16));
3390c582b7e3Smrg}
3391c582b7e3Smrg
3392c582b7e3Smrg/* Read PLL2 registers. */
3393c582b7e3Smrgstatic void R128SavePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr save)
3394c582b7e3Smrg{
3395c582b7e3Smrg    save->p2pll_ref_div        = INPLL(pScrn, R128_P2PLL_REF_DIV);
3396c582b7e3Smrg    save->p2pll_div_0          = INPLL(pScrn, R128_P2PLL_DIV_0);
3397c582b7e3Smrg    save->htotal_cntl2         = INPLL(pScrn, R128_HTOTAL2_CNTL);
3398c582b7e3Smrg
3399c582b7e3Smrg    R128TRACE(("Read: 0x%08x 0x%08x 0x%08x\n",
3400c582b7e3Smrg	       save->p2pll_ref_div,
3401c582b7e3Smrg	       save->p2pll_div_0,
3402c582b7e3Smrg	       save->htotal_cntl2));
3403c582b7e3Smrg    R128TRACE(("Read: rd=%d, fd=%d, pd=%d\n",
3404c582b7e3Smrg	       save->p2pll_ref_div & R128_P2PLL_REF_DIV_MASK,
3405c582b7e3Smrg	       save->p2pll_div_0 & R128_P2PLL_FB0_DIV_MASK,
3406c582b7e3Smrg	       (save->p2pll_div_0 & R128_P2PLL_POST0_DIV_MASK) >> 16));
3407c582b7e3Smrg}
3408c582b7e3Smrg
3409c582b7e3Smrg/* Read DDA registers. */
3410c582b7e3Smrgstatic void R128SaveDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save)
3411c582b7e3Smrg{
3412c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
3413c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
3414c582b7e3Smrg
3415c582b7e3Smrg    save->dda_config           = INREG(R128_DDA_CONFIG);
3416c582b7e3Smrg    save->dda_on_off           = INREG(R128_DDA_ON_OFF);
3417c582b7e3Smrg}
3418c582b7e3Smrg
3419c582b7e3Smrg/* Read DDA2 registers. */
3420c582b7e3Smrgstatic void R128SaveDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr save)
3421c582b7e3Smrg{
3422c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
3423c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
3424c582b7e3Smrg
3425c582b7e3Smrg    save->dda2_config           = INREG(R128_DDA2_CONFIG);
3426c582b7e3Smrg    save->dda2_on_off           = INREG(R128_DDA2_ON_OFF);
3427c582b7e3Smrg}
3428c582b7e3Smrg
3429c582b7e3Smrg/* Read palette data. */
3430c582b7e3Smrgstatic void R128SavePalette(ScrnInfoPtr pScrn, R128SavePtr save)
3431c582b7e3Smrg{
3432c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
3433c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
3434c582b7e3Smrg    int           i;
3435c582b7e3Smrg
3436c582b7e3Smrg    PAL_SELECT(1);
3437c582b7e3Smrg    INPAL_START(0);
3438c582b7e3Smrg    for (i = 0; i < 256; i++) save->palette2[i] = INPAL_NEXT();
3439c582b7e3Smrg    PAL_SELECT(0);
3440c582b7e3Smrg    INPAL_START(0);
3441c582b7e3Smrg    for (i = 0; i < 256; i++) save->palette[i] = INPAL_NEXT();
3442c582b7e3Smrg    save->palette_valid = TRUE;
3443c582b7e3Smrg}
3444c582b7e3Smrg
3445c582b7e3Smrg/* Save state that defines current video mode. */
3446c582b7e3Smrgstatic void R128SaveMode(ScrnInfoPtr pScrn, R128SavePtr save)
3447c582b7e3Smrg{
3448c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
3449c582b7e3Smrg
3450c582b7e3Smrg    R128TRACE(("R128SaveMode(%p)\n", save));
3451c582b7e3Smrg
3452c582b7e3Smrg    if(info->IsSecondary)
3453c582b7e3Smrg    {
3454c582b7e3Smrg        R128SaveCrtc2Registers(pScrn, save);
3455c582b7e3Smrg        R128SavePLL2Registers(pScrn, save);
3456c582b7e3Smrg        R128SaveDDA2Registers(pScrn, save);
3457c582b7e3Smrg    }
3458c582b7e3Smrg    else
3459c582b7e3Smrg    {
3460c582b7e3Smrg        R128SaveCommonRegisters(pScrn, save);
3461c582b7e3Smrg        R128SaveCrtcRegisters(pScrn, save);
3462c582b7e3Smrg        if((info->DisplayType == MT_DFP) ||
3463c582b7e3Smrg           (info->DisplayType == MT_LCD))
3464c582b7e3Smrg        {
3465c582b7e3Smrg 	    R128SaveFPRegisters(pScrn, save);
3466c582b7e3Smrg        }
3467c582b7e3Smrg        R128SavePLLRegisters(pScrn, save);
3468c582b7e3Smrg        R128SaveDDARegisters(pScrn, save);
3469c582b7e3Smrg        R128SavePalette(pScrn, save);
3470c582b7e3Smrg    }
3471c582b7e3Smrg
3472c582b7e3Smrg    R128TRACE(("R128SaveMode returns %p\n", save));
3473c582b7e3Smrg}
3474c582b7e3Smrg
3475c582b7e3Smrg/* Save everything needed to restore the original VC state. */
3476c582b7e3Smrgstatic void R128Save(ScrnInfoPtr pScrn)
3477c582b7e3Smrg{
3478c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
3479c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
3480c582b7e3Smrg    R128SavePtr   save      = &info->SavedReg;
3481c582b7e3Smrg
3482c582b7e3Smrg    R128TRACE(("R128Save\n"));
348379e5230eSmacallan#ifndef AVOID_FBDEV
3484c582b7e3Smrg    if (info->FBDev) {
3485c582b7e3Smrg	fbdevHWSave(pScrn);
3486c582b7e3Smrg	return;
3487c582b7e3Smrg    }
348879e5230eSmacallan#endif
3489c582b7e3Smrg
3490c582b7e3Smrg    if (!info->IsSecondary) {
3491c582b7e3Smrg#ifdef WITH_VGAHW
3492c582b7e3Smrg        if (info->VGAAccess) {
3493c582b7e3Smrg            vgaHWPtr hwp = VGAHWPTR(pScrn);
3494c582b7e3Smrg
3495c582b7e3Smrg            vgaHWUnlock(hwp);
3496c582b7e3Smrg# if defined(__powerpc__)
3497c582b7e3Smrg            /* temporary hack to prevent crashing on PowerMacs when trying to
3498c582b7e3Smrg             * read VGA fonts and colormap, will find a better solution
3499c582b7e3Smrg             * in the future. TODO: Check if there's actually some VGA stuff
3500c582b7e3Smrg             * setup in the card at all !!
3501c582b7e3Smrg             */
3502c582b7e3Smrg            vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE); /* Save mode only */
3503c582b7e3Smrg# else
3504c582b7e3Smrg            /* Save mode * & fonts & cmap */
3505c582b7e3Smrg            vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS);
3506c582b7e3Smrg# endif
3507c582b7e3Smrg            vgaHWLock(hwp);
3508c582b7e3Smrg        }
3509c582b7e3Smrg#endif
3510c582b7e3Smrg        save->dp_datatype      = INREG(R128_DP_DATATYPE);
3511c582b7e3Smrg        save->gen_reset_cntl   = INREG(R128_GEN_RESET_CNTL);
3512c582b7e3Smrg        save->clock_cntl_index = INREG(R128_CLOCK_CNTL_INDEX);
3513c582b7e3Smrg        save->amcgpio_en_reg   = INREG(R128_AMCGPIO_EN_REG);
3514c582b7e3Smrg        save->amcgpio_mask     = INREG(R128_AMCGPIO_MASK);
3515c582b7e3Smrg    }
3516c582b7e3Smrg
3517c582b7e3Smrg    R128SaveMode(pScrn, save);
3518c582b7e3Smrg
3519c582b7e3Smrg}
3520c582b7e3Smrg
3521c582b7e3Smrg/* Restore the original (text) mode. */
3522c582b7e3Smrgstatic void R128Restore(ScrnInfoPtr pScrn)
3523c582b7e3Smrg{
3524c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
3525c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
3526c582b7e3Smrg    R128SavePtr   restore   = &info->SavedReg;
3527c582b7e3Smrg
3528c582b7e3Smrg    R128TRACE(("R128Restore\n"));
352979e5230eSmacallan#ifndef AVOID_FBDEV
3530c582b7e3Smrg    if (info->FBDev) {
3531c582b7e3Smrg	fbdevHWRestore(pScrn);
3532c582b7e3Smrg	return;
3533c582b7e3Smrg    }
353479e5230eSmacallan#endif
3535c582b7e3Smrg    R128Blank(pScrn);
3536c582b7e3Smrg
3537c582b7e3Smrg    if (!info->IsSecondary) {
3538c582b7e3Smrg        OUTREG(R128_AMCGPIO_MASK,     restore->amcgpio_mask);
3539c582b7e3Smrg        OUTREG(R128_AMCGPIO_EN_REG,   restore->amcgpio_en_reg);
3540c582b7e3Smrg        OUTREG(R128_CLOCK_CNTL_INDEX, restore->clock_cntl_index);
3541c582b7e3Smrg        OUTREG(R128_GEN_RESET_CNTL,   restore->gen_reset_cntl);
3542c582b7e3Smrg        OUTREG(R128_DP_DATATYPE,      restore->dp_datatype);
3543c582b7e3Smrg    }
3544c582b7e3Smrg
3545c582b7e3Smrg    R128RestoreMode(pScrn, restore);
35469e881af1Smacallan
35479e881af1Smacallan    if (!info->IsSecondary) {
35489e881af1Smacallan        OUTREG(R128_AMCGPIO_MASK,     restore->amcgpio_mask);
35499e881af1Smacallan        OUTREG(R128_AMCGPIO_EN_REG,   restore->amcgpio_en_reg);
35509e881af1Smacallan        OUTREG(R128_CLOCK_CNTL_INDEX, restore->clock_cntl_index);
35519e881af1Smacallan        OUTREG(R128_GEN_RESET_CNTL,   restore->gen_reset_cntl);
35529e881af1Smacallan        OUTREG(R128_DP_DATATYPE,      restore->dp_datatype);
35539e881af1Smacallan    }
35549e881af1Smacallan
3555c582b7e3Smrg#ifdef WITH_VGAHW
3556c582b7e3Smrg    if (info->VGAAccess) {
3557c582b7e3Smrg        vgaHWPtr hwp = VGAHWPTR(pScrn);
3558c582b7e3Smrg        if (!info->IsSecondary) {
3559c582b7e3Smrg            vgaHWUnlock(hwp);
3560c582b7e3Smrg# if defined(__powerpc__)
3561c582b7e3Smrg            /* Temporary hack to prevent crashing on PowerMacs when trying to
3562c582b7e3Smrg             * write VGA fonts, will find a better solution in the future
3563c582b7e3Smrg             */
3564c582b7e3Smrg            vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE );
3565c582b7e3Smrg# else
3566c582b7e3Smrg            vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS );
3567c582b7e3Smrg# endif
3568c582b7e3Smrg            vgaHWLock(hwp);
3569c582b7e3Smrg        } else {
3570c582b7e3Smrg            R128EntPtr  pR128Ent = R128EntPriv(pScrn);
3571c582b7e3Smrg            ScrnInfoPtr   pScrn0 = pR128Ent->pPrimaryScrn;
3572c582b7e3Smrg            R128InfoPtr info0 = R128PTR(pScrn0);
3573c582b7e3Smrg            vgaHWPtr      hwp0;
3574c582b7e3Smrg
3575c582b7e3Smrg            if (info0->VGAAccess) {
3576c582b7e3Smrg                hwp0 = VGAHWPTR(pScrn0);
3577c582b7e3Smrg                vgaHWUnlock(hwp0);
3578c582b7e3Smrg#if defined(__powerpc__)
3579c582b7e3Smrg                vgaHWRestore(pScrn0, &hwp0->SavedReg, VGA_SR_MODE);
3580c582b7e3Smrg#else
3581c582b7e3Smrg                vgaHWRestore(pScrn0, &hwp0->SavedReg, VGA_SR_MODE | VGA_SR_FONTS );
3582c582b7e3Smrg#endif
3583c582b7e3Smrg                vgaHWLock(hwp0);
3584c582b7e3Smrg            }
3585c582b7e3Smrg        }
3586c582b7e3Smrg    }
3587c582b7e3Smrg#endif
3588c582b7e3Smrg
3589c582b7e3Smrg    R128WaitForVerticalSync(pScrn);
3590c582b7e3Smrg    R128Unblank(pScrn);
3591c582b7e3Smrg}
3592c582b7e3Smrg
3593c582b7e3Smrg/* Define common registers for requested video mode. */
3594c582b7e3Smrgstatic void R128InitCommonRegisters(R128SavePtr save, R128InfoPtr info)
3595c582b7e3Smrg{
3596c582b7e3Smrg    save->ovr_clr            = 0;
3597c582b7e3Smrg    save->ovr_wid_left_right = 0;
3598c582b7e3Smrg    save->ovr_wid_top_bottom = 0;
3599c582b7e3Smrg    save->ov0_scale_cntl     = 0;
3600c582b7e3Smrg    save->mpp_tb_config      = 0;
3601c582b7e3Smrg    save->mpp_gp_config      = 0;
3602c582b7e3Smrg    save->subpic_cntl        = 0;
3603c582b7e3Smrg    save->viph_control       = 0;
3604c582b7e3Smrg    save->i2c_cntl_1         = 0;
360584354367Smrg#ifdef R128DRI
3606c582b7e3Smrg    save->gen_int_cntl       = info->gen_int_cntl;
3607c582b7e3Smrg#else
3608c582b7e3Smrg    save->gen_int_cntl       = 0;
3609c582b7e3Smrg#endif
3610c582b7e3Smrg    save->cap0_trig_cntl     = 0;
3611c582b7e3Smrg    save->cap1_trig_cntl     = 0;
3612c582b7e3Smrg    save->bus_cntl           = info->BusCntl;
3613c582b7e3Smrg    /*
3614c582b7e3Smrg     * If bursts are enabled, turn on discards and aborts
3615c582b7e3Smrg     */
3616c582b7e3Smrg    if (save->bus_cntl & (R128_BUS_WRT_BURST|R128_BUS_READ_BURST))
3617c582b7e3Smrg	save->bus_cntl |= R128_BUS_RD_DISCARD_EN | R128_BUS_RD_ABORT_EN;
3618c582b7e3Smrg}
3619c582b7e3Smrg
3620c582b7e3Smrg/* Define CRTC registers for requested video mode. */
3621c582b7e3Smrgstatic Bool R128InitCrtcRegisters(ScrnInfoPtr pScrn, R128SavePtr save,
3622c582b7e3Smrg				  DisplayModePtr mode, R128InfoPtr info)
3623c582b7e3Smrg{
3624c582b7e3Smrg    int    format;
3625c582b7e3Smrg    int    hsync_start;
3626c582b7e3Smrg    int    hsync_wid;
3627c582b7e3Smrg    int    hsync_fudge;
3628c582b7e3Smrg    int    vsync_wid;
3629c582b7e3Smrg    int    hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 };
3630c582b7e3Smrg    int    hsync_fudge_fp[]      = { 0x12, 0x11, 0x09, 0x09, 0x05, 0x05 };
3631c582b7e3Smrg//   int    hsync_fudge_fp_crt[]  = { 0x12, 0x10, 0x08, 0x08, 0x04, 0x04 };
3632c582b7e3Smrg
3633c582b7e3Smrg    switch (info->CurrentLayout.pixel_code) {
3634c582b7e3Smrg    case 4:  format = 1; break;
3635c582b7e3Smrg    case 8:  format = 2; break;
3636c582b7e3Smrg    case 15: format = 3; break;      /*  555 */
3637c582b7e3Smrg    case 16: format = 4; break;      /*  565 */
3638c582b7e3Smrg    case 24: format = 5; break;      /*  RGB */
3639c582b7e3Smrg    case 32: format = 6; break;      /* xRGB */
3640c582b7e3Smrg    default:
3641c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
3642c582b7e3Smrg		   "Unsupported pixel depth (%d)\n",
3643c582b7e3Smrg		   info->CurrentLayout.bitsPerPixel);
3644c582b7e3Smrg	return FALSE;
3645c582b7e3Smrg    }
3646c582b7e3Smrg
3647c582b7e3Smrg    if ((info->DisplayType == MT_DFP) ||
3648c582b7e3Smrg        (info->DisplayType == MT_LCD))
3649c582b7e3Smrg	hsync_fudge = hsync_fudge_fp[format-1];
3650c582b7e3Smrg    else
3651c582b7e3Smrg        hsync_fudge = hsync_fudge_default[format-1];
3652c582b7e3Smrg
3653c582b7e3Smrg    save->crtc_gen_cntl = (R128_CRTC_EXT_DISP_EN
3654c582b7e3Smrg			  | R128_CRTC_EN
3655c582b7e3Smrg			  | (format << 8)
3656c582b7e3Smrg			  | ((mode->Flags & V_DBLSCAN)
3657c582b7e3Smrg			     ? R128_CRTC_DBL_SCAN_EN
3658c582b7e3Smrg			     : 0)
3659c582b7e3Smrg			  | ((mode->Flags & V_INTERLACE)
3660c582b7e3Smrg			     ? R128_CRTC_INTERLACE_EN
3661c582b7e3Smrg			     : 0)
3662c582b7e3Smrg			  | ((mode->Flags & V_CSYNC)
3663c582b7e3Smrg			     ? R128_CRTC_CSYNC_EN
3664c582b7e3Smrg			     : 0));
3665c582b7e3Smrg
3666c582b7e3Smrg    if((info->DisplayType == MT_DFP) ||
3667c582b7e3Smrg       (info->DisplayType == MT_LCD))
3668c582b7e3Smrg    {
3669c582b7e3Smrg        save->crtc_ext_cntl = R128_VGA_ATI_LINEAR |
3670c582b7e3Smrg        			  R128_XCRT_CNT_EN;
3671c582b7e3Smrg        save->crtc_gen_cntl &= ~(R128_CRTC_DBL_SCAN_EN |
3672c582b7e3Smrg                                  R128_CRTC_INTERLACE_EN);
3673c582b7e3Smrg    }
3674c582b7e3Smrg    else
3675c582b7e3Smrg        save->crtc_ext_cntl = R128_VGA_ATI_LINEAR |
3676c582b7e3Smrg			      R128_XCRT_CNT_EN |
3677c582b7e3Smrg			      R128_CRTC_CRT_ON;
3678c582b7e3Smrg
3679c582b7e3Smrg    save->dac_cntl      = (R128_DAC_MASK_ALL
3680c582b7e3Smrg			   | R128_DAC_VGA_ADR_EN
3681c582b7e3Smrg			   | (info->dac6bits ? 0 : R128_DAC_8BIT_EN));
3682c582b7e3Smrg
3683c582b7e3Smrg
3684c582b7e3Smrg    if(info->isDFP && !info->isPro2)
3685c582b7e3Smrg    {
3686c582b7e3Smrg        if(info->PanelXRes < mode->CrtcHDisplay)
3687c582b7e3Smrg            mode->HDisplay = mode->CrtcHDisplay = info->PanelXRes;
3688c582b7e3Smrg        if(info->PanelYRes < mode->CrtcVDisplay)
3689c582b7e3Smrg            mode->VDisplay = mode->CrtcVDisplay = info->PanelYRes;
3690c582b7e3Smrg        mode->CrtcHTotal = mode->CrtcHDisplay + info->HBlank;
3691c582b7e3Smrg        mode->CrtcHSyncStart = mode->CrtcHDisplay + info->HOverPlus;
3692c582b7e3Smrg        mode->CrtcHSyncEnd = mode->CrtcHSyncStart + info->HSyncWidth;
3693c582b7e3Smrg        mode->CrtcVTotal = mode->CrtcVDisplay + info->VBlank;
3694c582b7e3Smrg        mode->CrtcVSyncStart = mode->CrtcVDisplay + info->VOverPlus;
3695c582b7e3Smrg        mode->CrtcVSyncEnd = mode->CrtcVSyncStart + info->VSyncWidth;
3696c582b7e3Smrg    }
3697c582b7e3Smrg
3698c582b7e3Smrg    save->crtc_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0xffff)
3699c582b7e3Smrg			      | (((mode->CrtcHDisplay / 8) - 1) << 16));
3700c582b7e3Smrg
3701c582b7e3Smrg    hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8;
3702c582b7e3Smrg    if (!hsync_wid)       hsync_wid = 1;
3703c582b7e3Smrg    if (hsync_wid > 0x3f) hsync_wid = 0x3f;
3704c582b7e3Smrg
3705c582b7e3Smrg    hsync_start = mode->CrtcHSyncStart - 8 + hsync_fudge;
3706c582b7e3Smrg
3707c582b7e3Smrg    save->crtc_h_sync_strt_wid = ((hsync_start & 0xfff)
3708c582b7e3Smrg				 | (hsync_wid << 16)
3709c582b7e3Smrg				 | ((mode->Flags & V_NHSYNC)
3710c582b7e3Smrg				    ? R128_CRTC_H_SYNC_POL
3711c582b7e3Smrg				    : 0));
3712c582b7e3Smrg
3713c582b7e3Smrg#if 1
3714c582b7e3Smrg				/* This works for double scan mode. */
3715c582b7e3Smrg    save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff)
3716c582b7e3Smrg			      | ((mode->CrtcVDisplay - 1) << 16));
3717c582b7e3Smrg#else
3718c582b7e3Smrg				/* This is what cce/nbmode.c example code
3719c582b7e3Smrg				   does -- is this correct? */
3720c582b7e3Smrg    save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff)
3721c582b7e3Smrg			      | ((mode->CrtcVDisplay
3722c582b7e3Smrg				  * ((mode->Flags & V_DBLSCAN) ? 2 : 1) - 1)
3723c582b7e3Smrg				 << 16));
3724c582b7e3Smrg#endif
3725c582b7e3Smrg
3726c582b7e3Smrg    vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart;
3727c582b7e3Smrg    if (!vsync_wid)       vsync_wid = 1;
3728c582b7e3Smrg    if (vsync_wid > 0x1f) vsync_wid = 0x1f;
3729c582b7e3Smrg
3730c582b7e3Smrg    save->crtc_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff)
3731c582b7e3Smrg				 | (vsync_wid << 16)
3732c582b7e3Smrg				 | ((mode->Flags & V_NVSYNC)
3733c582b7e3Smrg				    ? R128_CRTC_V_SYNC_POL
3734c582b7e3Smrg				    : 0));
3735c582b7e3Smrg    save->crtc_offset      = 0;
3736c582b7e3Smrg    save->crtc_offset_cntl = 0;
3737c582b7e3Smrg    save->crtc_pitch       = info->CurrentLayout.displayWidth / 8;
3738c582b7e3Smrg
3739c582b7e3Smrg    R128TRACE(("Pitch = %d bytes (virtualX = %d, displayWidth = %d)\n",
3740c582b7e3Smrg	       save->crtc_pitch, pScrn->virtualX, info->CurrentLayout.displayWidth));
3741c582b7e3Smrg
3742c582b7e3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN
3743c582b7e3Smrg    /* Change the endianness of the aperture */
3744c582b7e3Smrg    switch (info->CurrentLayout.pixel_code) {
3745c582b7e3Smrg    case 15:
3746c582b7e3Smrg    case 16: save->config_cntl |= APER_0_BIG_ENDIAN_16BPP_SWAP; break;
3747c582b7e3Smrg    case 32: save->config_cntl |= APER_0_BIG_ENDIAN_32BPP_SWAP; break;
3748c582b7e3Smrg    default: break;
3749c582b7e3Smrg    }
3750c582b7e3Smrg#endif
3751c582b7e3Smrg
3752c582b7e3Smrg    return TRUE;
3753c582b7e3Smrg}
3754c582b7e3Smrg
3755c582b7e3Smrg/* Define CRTC2 registers for requested video mode. */
3756c582b7e3Smrgstatic Bool R128InitCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
3757c582b7e3Smrg				  DisplayModePtr mode, R128InfoPtr info)
3758c582b7e3Smrg{
3759c582b7e3Smrg    int    format;
3760c582b7e3Smrg    int    hsync_start;
3761c582b7e3Smrg    int    hsync_wid;
3762c582b7e3Smrg    int    hsync_fudge;
3763c582b7e3Smrg    int    vsync_wid;
3764c582b7e3Smrg    int    bytpp;
3765c582b7e3Smrg    int    hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 };
3766c582b7e3Smrg
3767c582b7e3Smrg    switch (info->CurrentLayout.pixel_code) {
3768c582b7e3Smrg    case 4:  format = 1; bytpp = 0; break;
3769c582b7e3Smrg    case 8:  format = 2; bytpp = 1; break;
3770c582b7e3Smrg    case 15: format = 3; bytpp = 2; break;      /*  555 */
3771c582b7e3Smrg    case 16: format = 4; bytpp = 2; break;      /*  565 */
3772c582b7e3Smrg    case 24: format = 5; bytpp = 3; break;      /*  RGB */
3773c582b7e3Smrg    case 32: format = 6; bytpp = 4; break;      /* xRGB */
3774c582b7e3Smrg    default:
3775c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
3776c582b7e3Smrg		   "Unsupported pixel depth (%d)\n", info->CurrentLayout.bitsPerPixel);
3777c582b7e3Smrg	return FALSE;
3778c582b7e3Smrg    }
3779c582b7e3Smrg    R128TRACE(("Format = %d (%d bytes per pixel)\n", format, bytpp));
3780c582b7e3Smrg
3781c582b7e3Smrg    hsync_fudge = hsync_fudge_default[format-1];
3782c582b7e3Smrg
3783c582b7e3Smrg    save->crtc2_gen_cntl = (R128_CRTC2_EN
3784c582b7e3Smrg			  | (format << 8)
3785c582b7e3Smrg			  | ((mode->Flags & V_DBLSCAN)
3786c582b7e3Smrg			     ? R128_CRTC2_DBL_SCAN_EN
3787c582b7e3Smrg			     : 0));
3788c582b7e3Smrg/*
3789c582b7e3Smrg    save->crtc2_gen_cntl &= ~R128_CRTC_EXT_DISP_EN;
3790c582b7e3Smrg    save->crtc2_gen_cntl |= (1 << 21);
3791c582b7e3Smrg*/
3792c582b7e3Smrg    save->crtc2_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0xffff)
3793c582b7e3Smrg			      | (((mode->CrtcHDisplay / 8) - 1) << 16));
3794c582b7e3Smrg
3795c582b7e3Smrg    hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8;
3796c582b7e3Smrg    if (!hsync_wid)       hsync_wid = 1;
3797c582b7e3Smrg    if (hsync_wid > 0x3f) hsync_wid = 0x3f;
3798c582b7e3Smrg
3799c582b7e3Smrg    hsync_start = mode->CrtcHSyncStart - 8 + hsync_fudge;
3800c582b7e3Smrg
3801c582b7e3Smrg    save->crtc2_h_sync_strt_wid = ((hsync_start & 0xfff)
3802c582b7e3Smrg				 | (hsync_wid << 16)
3803c582b7e3Smrg				 | ((mode->Flags & V_NHSYNC)
3804c582b7e3Smrg				    ? R128_CRTC2_H_SYNC_POL
3805c582b7e3Smrg				    : 0));
3806c582b7e3Smrg
3807c582b7e3Smrg#if 1
3808c582b7e3Smrg				/* This works for double scan mode. */
3809c582b7e3Smrg    save->crtc2_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff)
3810c582b7e3Smrg			      | ((mode->CrtcVDisplay - 1) << 16));
3811c582b7e3Smrg#else
3812c582b7e3Smrg				/* This is what cce/nbmode.c example code
3813c582b7e3Smrg				   does -- is this correct? */
3814c582b7e3Smrg    save->crtc2_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff)
3815c582b7e3Smrg			      | ((mode->CrtcVDisplay
3816c582b7e3Smrg				  * ((mode->Flags & V_DBLSCAN) ? 2 : 1) - 1)
3817c582b7e3Smrg				 << 16));
3818c582b7e3Smrg#endif
3819c582b7e3Smrg
3820c582b7e3Smrg    vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart;
3821c582b7e3Smrg    if (!vsync_wid)       vsync_wid = 1;
3822c582b7e3Smrg    if (vsync_wid > 0x1f) vsync_wid = 0x1f;
3823c582b7e3Smrg
3824c582b7e3Smrg    save->crtc2_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff)
3825c582b7e3Smrg				 | (vsync_wid << 16)
3826c582b7e3Smrg				 | ((mode->Flags & V_NVSYNC)
3827c582b7e3Smrg				    ? R128_CRTC2_V_SYNC_POL
3828c582b7e3Smrg				    : 0));
3829c582b7e3Smrg
3830c582b7e3Smrg    save->crtc2_offset      = 0;
3831c582b7e3Smrg    save->crtc2_offset_cntl = 0;
3832c582b7e3Smrg
3833c582b7e3Smrg    save->crtc2_pitch       = info->CurrentLayout.displayWidth / 8;
3834c582b7e3Smrg
3835c582b7e3Smrg    R128TRACE(("Pitch = %d bytes (virtualX = %d, displayWidth = %d)\n",
3836c582b7e3Smrg		 save->crtc2_pitch, pScrn->virtualX,
3837c582b7e3Smrg		 info->CurrentLayout.displayWidth));
3838c582b7e3Smrg    return TRUE;
3839c582b7e3Smrg}
3840c582b7e3Smrg
3841c582b7e3Smrg/* Define CRTC registers for requested video mode. */
3842c582b7e3Smrgstatic void R128InitFPRegisters(R128SavePtr orig, R128SavePtr save,
3843c582b7e3Smrg				DisplayModePtr mode, R128InfoPtr info)
3844c582b7e3Smrg{
3845c582b7e3Smrg    int   xres = mode->CrtcHDisplay;
3846c582b7e3Smrg    int   yres = mode->CrtcVDisplay;
3847c582b7e3Smrg    float Hratio, Vratio;
3848c582b7e3Smrg
3849c582b7e3Smrg    if (info->BIOSDisplay == R128_BIOS_DISPLAY_CRT) {
3850c582b7e3Smrg        save->crtc_ext_cntl  |= R128_CRTC_CRT_ON;
3851c582b7e3Smrg        save->crtc2_gen_cntl  = 0;
3852c582b7e3Smrg        save->fp_gen_cntl     = orig->fp_gen_cntl;
3853c582b7e3Smrg        save->fp_gen_cntl    &= ~(R128_FP_FPON |
3854c582b7e3Smrg            R128_FP_CRTC_USE_SHADOW_VEND |
3855c582b7e3Smrg            R128_FP_CRTC_HORZ_DIV2_EN |
3856c582b7e3Smrg            R128_FP_CRTC_HOR_CRT_DIV2_DIS |
3857c582b7e3Smrg            R128_FP_USE_SHADOW_EN);
3858c582b7e3Smrg        save->fp_gen_cntl    |= (R128_FP_SEL_CRTC2 |
3859c582b7e3Smrg                                 R128_FP_CRTC_DONT_SHADOW_VPAR);
3860c582b7e3Smrg        save->fp_panel_cntl   = orig->fp_panel_cntl & (CARD32)~R128_FP_DIGON;
3861c582b7e3Smrg        save->lvds_gen_cntl   = orig->lvds_gen_cntl &
3862c582b7e3Smrg				    (CARD32)~(R128_LVDS_ON | R128_LVDS_BLON);
3863c582b7e3Smrg        return;
3864c582b7e3Smrg    }
3865c582b7e3Smrg
3866c582b7e3Smrg    if (xres > info->PanelXRes) xres = info->PanelXRes;
3867c582b7e3Smrg    if (yres > info->PanelYRes) yres = info->PanelYRes;
3868c582b7e3Smrg
3869c582b7e3Smrg    Hratio = (float)xres/(float)info->PanelXRes;
3870c582b7e3Smrg    Vratio = (float)yres/(float)info->PanelYRes;
3871c582b7e3Smrg
3872c582b7e3Smrg    save->fp_horz_stretch =
3873c582b7e3Smrg	(((((int)(Hratio * R128_HORZ_STRETCH_RATIO_MAX + 0.5))
3874c582b7e3Smrg	   & R128_HORZ_STRETCH_RATIO_MASK) << R128_HORZ_STRETCH_RATIO_SHIFT) |
3875c582b7e3Smrg       (orig->fp_horz_stretch & (R128_HORZ_PANEL_SIZE |
3876c582b7e3Smrg                                 R128_HORZ_FP_LOOP_STRETCH |
3877c582b7e3Smrg                                 R128_HORZ_STRETCH_RESERVED)));
3878c582b7e3Smrg    save->fp_horz_stretch &= ~R128_HORZ_AUTO_RATIO_FIX_EN;
3879c582b7e3Smrg    save->fp_horz_stretch &= ~R128_AUTO_HORZ_RATIO;
3880c582b7e3Smrg    if (xres == info->PanelXRes)
3881c582b7e3Smrg         save->fp_horz_stretch &= ~(R128_HORZ_STRETCH_BLEND | R128_HORZ_STRETCH_ENABLE);
3882c582b7e3Smrg    else
3883c582b7e3Smrg         save->fp_horz_stretch |=  (R128_HORZ_STRETCH_BLEND | R128_HORZ_STRETCH_ENABLE);
3884c582b7e3Smrg
3885c582b7e3Smrg    save->fp_vert_stretch =
3886c582b7e3Smrg	(((((int)(Vratio * R128_VERT_STRETCH_RATIO_MAX + 0.5))
3887c582b7e3Smrg	   & R128_VERT_STRETCH_RATIO_MASK) << R128_VERT_STRETCH_RATIO_SHIFT) |
3888c582b7e3Smrg	 (orig->fp_vert_stretch & (R128_VERT_PANEL_SIZE |
3889c582b7e3Smrg				   R128_VERT_STRETCH_RESERVED)));
3890c582b7e3Smrg    save->fp_vert_stretch &= ~R128_VERT_AUTO_RATIO_EN;
3891c582b7e3Smrg    if (yres == info->PanelYRes)
3892c582b7e3Smrg        save->fp_vert_stretch &= ~(R128_VERT_STRETCH_ENABLE | R128_VERT_STRETCH_BLEND);
3893c582b7e3Smrg    else
3894c582b7e3Smrg        save->fp_vert_stretch |=  (R128_VERT_STRETCH_ENABLE | R128_VERT_STRETCH_BLEND);
3895c582b7e3Smrg
3896c582b7e3Smrg    save->fp_gen_cntl = (orig->fp_gen_cntl &
3897c582b7e3Smrg			 (CARD32)~(R128_FP_SEL_CRTC2 |
3898c582b7e3Smrg				   R128_FP_CRTC_USE_SHADOW_VEND |
3899c582b7e3Smrg				   R128_FP_CRTC_HORZ_DIV2_EN |
3900c582b7e3Smrg				   R128_FP_CRTC_HOR_CRT_DIV2_DIS |
3901c582b7e3Smrg				   R128_FP_USE_SHADOW_EN));
3902c582b7e3Smrg
3903c582b7e3Smrg    save->fp_panel_cntl        = orig->fp_panel_cntl;
3904c582b7e3Smrg    save->lvds_gen_cntl        = orig->lvds_gen_cntl;
3905c582b7e3Smrg    save->tmds_crc             = orig->tmds_crc;
3906c582b7e3Smrg
3907c582b7e3Smrg    /* Disable CRT output by disabling CRT output and setting the CRT
3908c582b7e3Smrg       DAC to use CRTC2, which we set to 0's.  In the future, we will
3909c582b7e3Smrg       want to use the dual CRTC capabilities of the R128 to allow both
3910c582b7e3Smrg       the flat panel and external CRT to either simultaneously display
3911c582b7e3Smrg       the same image or display two different images. */
3912c582b7e3Smrg
3913c582b7e3Smrg
3914c582b7e3Smrg    if(!info->isDFP){
3915c582b7e3Smrg        if (info->BIOSDisplay == R128_BIOS_DISPLAY_FP_CRT) {
3916c582b7e3Smrg		save->crtc_ext_cntl  |= R128_CRTC_CRT_ON;
3917c582b7e3Smrg	} else if (info->BIOSDisplay == R128_DUALHEAD) {
3918c582b7e3Smrg		save->crtc_ext_cntl  |= R128_CRTC_CRT_ON;
3919c582b7e3Smrg		save->dac_cntl       |= R128_DAC_CRT_SEL_CRTC2;
3920c582b7e3Smrg		save->dac_cntl       |= R128_DAC_PALETTE2_SNOOP_EN;
3921c582b7e3Smrg        } else {
3922c582b7e3Smrg		save->crtc_ext_cntl  &= ~R128_CRTC_CRT_ON;
3923c582b7e3Smrg		save->dac_cntl       |= R128_DAC_CRT_SEL_CRTC2;
3924c582b7e3Smrg		save->crtc2_gen_cntl  = 0;
3925c582b7e3Smrg        }
3926c582b7e3Smrg    }
3927c582b7e3Smrg
3928c582b7e3Smrg    /* WARNING: Be careful about turning on the flat panel */
3929c582b7e3Smrg    if(info->isDFP){
3930c582b7e3Smrg        save->fp_gen_cntl = orig->fp_gen_cntl;
3931c582b7e3Smrg
3932c582b7e3Smrg        save->fp_gen_cntl &= ~(R128_FP_CRTC_USE_SHADOW_VEND |
3933c582b7e3Smrg                               R128_FP_CRTC_USE_SHADOW_ROWCUR |
3934c582b7e3Smrg                               R128_FP_CRTC_HORZ_DIV2_EN |
3935c582b7e3Smrg                               R128_FP_CRTC_HOR_CRT_DIV2_DIS |
3936c582b7e3Smrg                               R128_FP_CRT_SYNC_SEL |
3937c582b7e3Smrg                               R128_FP_USE_SHADOW_EN);
3938c582b7e3Smrg
3939c582b7e3Smrg        save->fp_panel_cntl  |= (R128_FP_DIGON | R128_FP_BLON);
3940c582b7e3Smrg        save->fp_gen_cntl    |= (R128_FP_FPON | R128_FP_TDMS_EN |
3941c582b7e3Smrg             R128_FP_CRTC_DONT_SHADOW_VPAR | R128_FP_CRTC_DONT_SHADOW_HEND);
3942c582b7e3Smrg        save->tmds_transmitter_cntl = (orig->tmds_transmitter_cntl
3943c582b7e3Smrg            & ~(CARD32)R128_TMDS_PLLRST) | R128_TMDS_PLLEN;
3944c582b7e3Smrg    }
3945c582b7e3Smrg    else
3946c582b7e3Smrg        save->lvds_gen_cntl  |= (R128_LVDS_ON | R128_LVDS_BLON);
3947c582b7e3Smrg
3948c582b7e3Smrg    save->fp_crtc_h_total_disp = save->crtc_h_total_disp;
3949c582b7e3Smrg    save->fp_crtc_v_total_disp = save->crtc_v_total_disp;
3950c582b7e3Smrg    save->fp_h_sync_strt_wid   = save->crtc_h_sync_strt_wid;
3951c582b7e3Smrg    save->fp_v_sync_strt_wid   = save->crtc_v_sync_strt_wid;
3952c582b7e3Smrg}
3953c582b7e3Smrg
3954c582b7e3Smrg/* Define PLL registers for requested video mode. */
3955c582b7e3Smrgstatic void R128InitPLLRegisters(ScrnInfoPtr pScrn, R128SavePtr save,
3956c582b7e3Smrg				R128PLLPtr pll, double dot_clock)
3957c582b7e3Smrg{
3958c582b7e3Smrg    unsigned long freq = dot_clock * 100;
3959c582b7e3Smrg    struct {
3960c582b7e3Smrg	int divider;
3961c582b7e3Smrg	int bitvalue;
3962c582b7e3Smrg    } *post_div,
3963c582b7e3Smrg      post_divs[]   = {
3964c582b7e3Smrg				/* From RAGE 128 VR/RAGE 128 GL Register
3965c582b7e3Smrg				   Reference Manual (Technical Reference
3966c582b7e3Smrg				   Manual P/N RRG-G04100-C Rev. 0.04), page
3967c582b7e3Smrg				   3-17 (PLL_DIV_[3:0]).  */
3968c582b7e3Smrg	{  1, 0 },              /* VCLK_SRC                 */
3969c582b7e3Smrg	{  2, 1 },              /* VCLK_SRC/2               */
3970c582b7e3Smrg	{  4, 2 },              /* VCLK_SRC/4               */
3971c582b7e3Smrg	{  8, 3 },              /* VCLK_SRC/8               */
3972c582b7e3Smrg
3973c582b7e3Smrg	{  3, 4 },              /* VCLK_SRC/3               */
3974c582b7e3Smrg				/* bitvalue = 5 is reserved */
3975c582b7e3Smrg	{  6, 6 },              /* VCLK_SRC/6               */
3976c582b7e3Smrg	{ 12, 7 },              /* VCLK_SRC/12              */
3977c582b7e3Smrg	{  0, 0 }
3978c582b7e3Smrg    };
3979c582b7e3Smrg
3980c582b7e3Smrg    if (freq > pll->max_pll_freq)      freq = pll->max_pll_freq;
3981c582b7e3Smrg    if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12;
3982c582b7e3Smrg
3983c582b7e3Smrg    for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
3984c582b7e3Smrg	save->pll_output_freq = post_div->divider * freq;
3985c582b7e3Smrg	if (save->pll_output_freq >= pll->min_pll_freq
3986c582b7e3Smrg	    && save->pll_output_freq <= pll->max_pll_freq) break;
3987c582b7e3Smrg    }
3988c582b7e3Smrg
3989c582b7e3Smrg    save->dot_clock_freq = freq;
3990c582b7e3Smrg    save->feedback_div   = R128Div(pll->reference_div * save->pll_output_freq,
3991c582b7e3Smrg				   pll->reference_freq);
3992c582b7e3Smrg    save->post_div       = post_div->divider;
3993c582b7e3Smrg
3994c582b7e3Smrg    R128TRACE(("dc=%d, of=%d, fd=%d, pd=%d\n",
3995c582b7e3Smrg	       save->dot_clock_freq,
3996c582b7e3Smrg	       save->pll_output_freq,
3997c582b7e3Smrg	       save->feedback_div,
3998c582b7e3Smrg	       save->post_div));
3999c582b7e3Smrg
4000c582b7e3Smrg    save->ppll_ref_div   = pll->reference_div;
4001c582b7e3Smrg    save->ppll_div_3     = (save->feedback_div | (post_div->bitvalue << 16));
4002c582b7e3Smrg    save->htotal_cntl    = 0;
4003c582b7e3Smrg
4004c582b7e3Smrg}
4005c582b7e3Smrg
4006c582b7e3Smrg/* Define PLL2 registers for requested video mode. */
400784354367Smrgstatic void R128InitPLL2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
400884354367Smrg				   R128PLLPtr pll, double dot_clock)
4009c582b7e3Smrg{
4010c582b7e3Smrg    unsigned long freq = dot_clock * 100;
4011c582b7e3Smrg    struct {
4012c582b7e3Smrg	int divider;
4013c582b7e3Smrg	int bitvalue;
4014c582b7e3Smrg    } *post_div,
4015c582b7e3Smrg      post_divs[]   = {
4016c582b7e3Smrg				/* From RAGE 128 VR/RAGE 128 GL Register
4017c582b7e3Smrg				   Reference Manual (Technical Reference
4018c582b7e3Smrg				   Manual P/N RRG-G04100-C Rev. 0.04), page
4019c582b7e3Smrg				   3-17 (PLL_DIV_[3:0]).  */
4020c582b7e3Smrg	{  1, 0 },              /* VCLK_SRC                 */
4021c582b7e3Smrg	{  2, 1 },              /* VCLK_SRC/2               */
4022c582b7e3Smrg	{  4, 2 },              /* VCLK_SRC/4               */
4023c582b7e3Smrg	{  8, 3 },              /* VCLK_SRC/8               */
4024c582b7e3Smrg
4025c582b7e3Smrg	{  3, 4 },              /* VCLK_SRC/3               */
4026c582b7e3Smrg				/* bitvalue = 5 is reserved */
4027c582b7e3Smrg	{  6, 6 },              /* VCLK_SRC/6               */
4028c582b7e3Smrg	{ 12, 7 },              /* VCLK_SRC/12              */
4029c582b7e3Smrg	{  0, 0 }
4030c582b7e3Smrg    };
4031c582b7e3Smrg
4032c582b7e3Smrg    if (freq > pll->max_pll_freq)      freq = pll->max_pll_freq;
4033c582b7e3Smrg    if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12;
4034c582b7e3Smrg
4035c582b7e3Smrg    for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
4036c582b7e3Smrg	save->pll_output_freq_2 = post_div->divider * freq;
4037c582b7e3Smrg	if (save->pll_output_freq_2 >= pll->min_pll_freq
4038c582b7e3Smrg	    && save->pll_output_freq_2 <= pll->max_pll_freq) break;
4039c582b7e3Smrg    }
4040c582b7e3Smrg
4041c582b7e3Smrg    save->dot_clock_freq_2 = freq;
4042c582b7e3Smrg    save->feedback_div_2   = R128Div(pll->reference_div
4043c582b7e3Smrg				     * save->pll_output_freq_2,
4044c582b7e3Smrg				     pll->reference_freq);
4045c582b7e3Smrg    save->post_div_2       = post_div->divider;
4046c582b7e3Smrg
4047c582b7e3Smrg    R128TRACE(("dc=%d, of=%d, fd=%d, pd=%d\n",
4048c582b7e3Smrg	       save->dot_clock_freq_2,
4049c582b7e3Smrg	       save->pll_output_freq_2,
4050c582b7e3Smrg	       save->feedback_div_2,
4051c582b7e3Smrg	       save->post_div_2));
4052c582b7e3Smrg
4053c582b7e3Smrg    save->p2pll_ref_div   = pll->reference_div;
4054c582b7e3Smrg    save->p2pll_div_0    = (save->feedback_div_2 | (post_div->bitvalue<<16));
4055c582b7e3Smrg    save->htotal_cntl2    = 0;
4056c582b7e3Smrg}
4057c582b7e3Smrg
4058c582b7e3Smrg/* Define DDA registers for requested video mode. */
4059c582b7e3Smrgstatic Bool R128InitDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save,
4060c582b7e3Smrg				 R128PLLPtr pll, R128InfoPtr info,
4061c582b7e3Smrg                                 DisplayModePtr mode)
4062c582b7e3Smrg{
4063c582b7e3Smrg    int         DisplayFifoWidth = 128;
4064c582b7e3Smrg    int         DisplayFifoDepth = 32;
4065c582b7e3Smrg    int         XclkFreq;
4066c582b7e3Smrg    int         VclkFreq;
4067c582b7e3Smrg    int         XclksPerTransfer;
4068c582b7e3Smrg    int         XclksPerTransferPrecise;
4069c582b7e3Smrg    int         UseablePrecision;
4070c582b7e3Smrg    int         Roff;
4071c582b7e3Smrg    int         Ron;
4072c582b7e3Smrg
4073c582b7e3Smrg    XclkFreq = pll->xclk;
4074c582b7e3Smrg
4075c582b7e3Smrg    VclkFreq = R128Div(pll->reference_freq * save->feedback_div,
4076c582b7e3Smrg		       pll->reference_div * save->post_div);
4077c582b7e3Smrg
4078c582b7e3Smrg    if(info->isDFP && !info->isPro2){
4079c582b7e3Smrg        if(info->PanelXRes != mode->CrtcHDisplay)
4080c582b7e3Smrg            VclkFreq = (VclkFreq * mode->CrtcHDisplay)/info->PanelXRes;
4081c582b7e3Smrg	}
4082c582b7e3Smrg
4083c582b7e3Smrg    XclksPerTransfer = R128Div(XclkFreq * DisplayFifoWidth,
4084c582b7e3Smrg			       VclkFreq * (info->CurrentLayout.pixel_bytes * 8));
4085c582b7e3Smrg
4086c582b7e3Smrg    UseablePrecision = R128MinBits(XclksPerTransfer) + 1;
4087c582b7e3Smrg
4088c582b7e3Smrg    XclksPerTransferPrecise = R128Div((XclkFreq * DisplayFifoWidth)
4089c582b7e3Smrg				      << (11 - UseablePrecision),
4090c582b7e3Smrg				      VclkFreq * (info->CurrentLayout.pixel_bytes * 8));
4091c582b7e3Smrg
4092c582b7e3Smrg    Roff  = XclksPerTransferPrecise * (DisplayFifoDepth - 4);
4093c582b7e3Smrg
4094c582b7e3Smrg    Ron   = (4 * info->ram->MB
4095c582b7e3Smrg	     + 3 * MAX(info->ram->Trcd - 2, 0)
4096c582b7e3Smrg	     + 2 * info->ram->Trp
4097c582b7e3Smrg	     + info->ram->Twr
4098c582b7e3Smrg	     + info->ram->CL
4099c582b7e3Smrg	     + info->ram->Tr2w
4100c582b7e3Smrg	     + XclksPerTransfer) << (11 - UseablePrecision);
4101c582b7e3Smrg
4102c582b7e3Smrg    if (Ron + info->ram->Rloop >= Roff) {
4103c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4104c582b7e3Smrg		   "(Ron = %d) + (Rloop = %d) >= (Roff = %d)\n",
4105c582b7e3Smrg		   Ron, info->ram->Rloop, Roff);
4106c582b7e3Smrg	return FALSE;
4107c582b7e3Smrg    }
4108c582b7e3Smrg
4109c582b7e3Smrg    save->dda_config = (XclksPerTransferPrecise
4110c582b7e3Smrg			| (UseablePrecision << 16)
4111c582b7e3Smrg			| (info->ram->Rloop << 20));
4112c582b7e3Smrg
4113c582b7e3Smrg    save->dda_on_off = (Ron << 16) | Roff;
4114c582b7e3Smrg
4115c582b7e3Smrg    R128TRACE(("XclkFreq = %d; VclkFreq = %d; per = %d, %d (useable = %d)\n",
4116c582b7e3Smrg	       XclkFreq,
4117c582b7e3Smrg	       VclkFreq,
4118c582b7e3Smrg	       XclksPerTransfer,
4119c582b7e3Smrg	       XclksPerTransferPrecise,
4120c582b7e3Smrg	       UseablePrecision));
4121c582b7e3Smrg    R128TRACE(("Roff = %d, Ron = %d, Rloop = %d\n",
4122c582b7e3Smrg	       Roff, Ron, info->ram->Rloop));
4123c582b7e3Smrg
4124c582b7e3Smrg    return TRUE;
4125c582b7e3Smrg}
4126c582b7e3Smrg
4127c582b7e3Smrg/* Define DDA2 registers for requested video mode. */
4128c582b7e3Smrgstatic Bool R128InitDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
4129c582b7e3Smrg				 R128PLLPtr pll, R128InfoPtr info,
4130c582b7e3Smrg                                 DisplayModePtr mode)
4131c582b7e3Smrg{
4132c582b7e3Smrg    int         DisplayFifoWidth = 128;
4133c582b7e3Smrg    int         DisplayFifoDepth = 32;
4134c582b7e3Smrg    int         XclkFreq;
4135c582b7e3Smrg    int         VclkFreq;
4136c582b7e3Smrg    int         XclksPerTransfer;
4137c582b7e3Smrg    int         XclksPerTransferPrecise;
4138c582b7e3Smrg    int         UseablePrecision;
4139c582b7e3Smrg    int         Roff;
4140c582b7e3Smrg    int         Ron;
4141c582b7e3Smrg
4142c582b7e3Smrg    XclkFreq = pll->xclk;
4143c582b7e3Smrg
4144c582b7e3Smrg    VclkFreq = R128Div(pll->reference_freq * save->feedback_div_2,
4145c582b7e3Smrg		       pll->reference_div * save->post_div_2);
4146c582b7e3Smrg
4147c582b7e3Smrg    if(info->isDFP && !info->isPro2){
4148c582b7e3Smrg        if(info->PanelXRes != mode->CrtcHDisplay)
4149c582b7e3Smrg            VclkFreq = (VclkFreq * mode->CrtcHDisplay)/info->PanelXRes;
4150c582b7e3Smrg	}
4151c582b7e3Smrg
4152c582b7e3Smrg    XclksPerTransfer = R128Div(XclkFreq * DisplayFifoWidth,
4153c582b7e3Smrg			       VclkFreq * (info->CurrentLayout.pixel_bytes * 8));
4154c582b7e3Smrg
4155c582b7e3Smrg    UseablePrecision = R128MinBits(XclksPerTransfer) + 1;
4156c582b7e3Smrg
4157c582b7e3Smrg    XclksPerTransferPrecise = R128Div((XclkFreq * DisplayFifoWidth)
4158c582b7e3Smrg				      << (11 - UseablePrecision),
4159c582b7e3Smrg				      VclkFreq * (info->CurrentLayout.pixel_bytes * 8));
4160c582b7e3Smrg
4161c582b7e3Smrg    Roff  = XclksPerTransferPrecise * (DisplayFifoDepth - 4);
4162c582b7e3Smrg
4163c582b7e3Smrg    Ron   = (4 * info->ram->MB
4164c582b7e3Smrg	     + 3 * MAX(info->ram->Trcd - 2, 0)
4165c582b7e3Smrg	     + 2 * info->ram->Trp
4166c582b7e3Smrg	     + info->ram->Twr
4167c582b7e3Smrg	     + info->ram->CL
4168c582b7e3Smrg	     + info->ram->Tr2w
4169c582b7e3Smrg	     + XclksPerTransfer) << (11 - UseablePrecision);
4170c582b7e3Smrg
4171c582b7e3Smrg
4172c582b7e3Smrg    if (Ron + info->ram->Rloop >= Roff) {
4173c582b7e3Smrg	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4174c582b7e3Smrg		   "(Ron = %d) + (Rloop = %d) >= (Roff = %d)\n",
4175c582b7e3Smrg		   Ron, info->ram->Rloop, Roff);
4176c582b7e3Smrg	return FALSE;
4177c582b7e3Smrg    }
4178c582b7e3Smrg
4179c582b7e3Smrg    save->dda2_config = (XclksPerTransferPrecise
4180c582b7e3Smrg			| (UseablePrecision << 16)
4181c582b7e3Smrg			| (info->ram->Rloop << 20));
4182c582b7e3Smrg
4183c582b7e3Smrg    /*save->dda2_on_off = (Ron << 16) | Roff;*/
4184c582b7e3Smrg    /* shift most be 18 otherwise there's corruption on crtc2 */
4185c582b7e3Smrg    save->dda2_on_off = (Ron << 18) | Roff;
4186c582b7e3Smrg
4187c582b7e3Smrg    R128TRACE(("XclkFreq = %d; VclkFreq = %d; per = %d, %d (useable = %d)\n",
4188c582b7e3Smrg	       XclkFreq,
4189c582b7e3Smrg	       VclkFreq,
4190c582b7e3Smrg	       XclksPerTransfer,
4191c582b7e3Smrg	       XclksPerTransferPrecise,
4192c582b7e3Smrg	       UseablePrecision));
4193c582b7e3Smrg    R128TRACE(("Roff = %d, Ron = %d, Rloop = %d\n",
4194c582b7e3Smrg	       Roff, Ron, info->ram->Rloop));
4195c582b7e3Smrg
4196c582b7e3Smrg    return TRUE;
4197c582b7e3Smrg}
4198c582b7e3Smrg
4199c582b7e3Smrg#if 0
4200c582b7e3Smrg/* Define initial palette for requested video mode.  This doesn't do
4201c582b7e3Smrg   anything for XFree86 4.0. */
4202c582b7e3Smrgstatic void R128InitPalette(R128SavePtr save)
4203c582b7e3Smrg{
4204c582b7e3Smrg    save->palette_valid = FALSE;
4205c582b7e3Smrg}
4206c582b7e3Smrg#endif
4207c582b7e3Smrg
4208c582b7e3Smrg/* Define registers for a requested video mode. */
4209c582b7e3Smrgstatic Bool R128Init(ScrnInfoPtr pScrn, DisplayModePtr mode, R128SavePtr save)
4210c582b7e3Smrg{
4211c582b7e3Smrg    R128InfoPtr info      = R128PTR(pScrn);
4212c582b7e3Smrg    double      dot_clock = mode->Clock/1000.0;
4213c582b7e3Smrg
4214c582b7e3Smrg#if R128_DEBUG
4215c582b7e3Smrg    ErrorF("%-12.12s %7.2f  %4d %4d %4d %4d  %4d %4d %4d %4d (%d,%d)",
4216c582b7e3Smrg	   mode->name,
4217c582b7e3Smrg	   dot_clock,
4218c582b7e3Smrg
4219c582b7e3Smrg	   mode->HDisplay,
4220c582b7e3Smrg	   mode->HSyncStart,
4221c582b7e3Smrg	   mode->HSyncEnd,
4222c582b7e3Smrg	   mode->HTotal,
4223c582b7e3Smrg
4224c582b7e3Smrg	   mode->VDisplay,
4225c582b7e3Smrg	   mode->VSyncStart,
4226c582b7e3Smrg	   mode->VSyncEnd,
4227c582b7e3Smrg	   mode->VTotal,
4228c582b7e3Smrg	   pScrn->depth,
4229c582b7e3Smrg	   pScrn->bitsPerPixel);
4230c582b7e3Smrg    if (mode->Flags & V_DBLSCAN)   ErrorF(" D");
4231c582b7e3Smrg    if (mode->Flags & V_CSYNC)     ErrorF(" C");
4232c582b7e3Smrg    if (mode->Flags & V_INTERLACE) ErrorF(" I");
4233c582b7e3Smrg    if (mode->Flags & V_PHSYNC)    ErrorF(" +H");
4234c582b7e3Smrg    if (mode->Flags & V_NHSYNC)    ErrorF(" -H");
4235c582b7e3Smrg    if (mode->Flags & V_PVSYNC)    ErrorF(" +V");
4236c582b7e3Smrg    if (mode->Flags & V_NVSYNC)    ErrorF(" -V");
4237c582b7e3Smrg    ErrorF("\n");
4238c582b7e3Smrg    ErrorF("%-12.12s %7.2f  %4d %4d %4d %4d  %4d %4d %4d %4d (%d,%d)",
4239c582b7e3Smrg	   mode->name,
4240c582b7e3Smrg	   dot_clock,
4241c582b7e3Smrg
4242c582b7e3Smrg	   mode->CrtcHDisplay,
4243c582b7e3Smrg	   mode->CrtcHSyncStart,
4244c582b7e3Smrg	   mode->CrtcHSyncEnd,
4245c582b7e3Smrg	   mode->CrtcHTotal,
4246c582b7e3Smrg
4247c582b7e3Smrg	   mode->CrtcVDisplay,
4248c582b7e3Smrg	   mode->CrtcVSyncStart,
4249c582b7e3Smrg	   mode->CrtcVSyncEnd,
4250c582b7e3Smrg	   mode->CrtcVTotal,
4251c582b7e3Smrg	   pScrn->depth,
4252c582b7e3Smrg	   pScrn->bitsPerPixel);
4253c582b7e3Smrg    if (mode->Flags & V_DBLSCAN)   ErrorF(" D");
4254c582b7e3Smrg    if (mode->Flags & V_CSYNC)     ErrorF(" C");
4255c582b7e3Smrg    if (mode->Flags & V_INTERLACE) ErrorF(" I");
4256c582b7e3Smrg    if (mode->Flags & V_PHSYNC)    ErrorF(" +H");
4257c582b7e3Smrg    if (mode->Flags & V_NHSYNC)    ErrorF(" -H");
4258c582b7e3Smrg    if (mode->Flags & V_PVSYNC)    ErrorF(" +V");
4259c582b7e3Smrg    if (mode->Flags & V_NVSYNC)    ErrorF(" -V");
4260c582b7e3Smrg    ErrorF("\n");
4261c582b7e3Smrg#endif
4262c582b7e3Smrg
4263c582b7e3Smrg    info->Flags = mode->Flags;
4264c582b7e3Smrg
4265c582b7e3Smrg    if(info->IsSecondary)
4266c582b7e3Smrg    {
4267c582b7e3Smrg        if (!R128InitCrtc2Registers(pScrn, save,
4268c582b7e3Smrg             pScrn->currentMode,info))
4269c582b7e3Smrg            return FALSE;
427084354367Smrg        R128InitPLL2Registers(pScrn, save, &info->pll, dot_clock);
4271c582b7e3Smrg        if (!R128InitDDA2Registers(pScrn, save, &info->pll, info, mode))
4272c582b7e3Smrg	    return FALSE;
4273c582b7e3Smrg    }
4274c582b7e3Smrg    else
4275c582b7e3Smrg    {
4276c582b7e3Smrg        R128InitCommonRegisters(save, info);
4277c582b7e3Smrg        if(!R128InitCrtcRegisters(pScrn, save, mode, info))
4278c582b7e3Smrg            return FALSE;
4279c582b7e3Smrg        if(dot_clock)
4280c582b7e3Smrg        {
4281c582b7e3Smrg            R128InitPLLRegisters(pScrn, save, &info->pll, dot_clock);
4282c582b7e3Smrg            if (!R128InitDDARegisters(pScrn, save, &info->pll, info, mode))
4283c582b7e3Smrg	        return FALSE;
4284c582b7e3Smrg        }
4285c582b7e3Smrg        else
4286c582b7e3Smrg        {
4287c582b7e3Smrg            save->ppll_ref_div         = info->SavedReg.ppll_ref_div;
4288c582b7e3Smrg            save->ppll_div_3           = info->SavedReg.ppll_div_3;
4289c582b7e3Smrg            save->htotal_cntl          = info->SavedReg.htotal_cntl;
4290c582b7e3Smrg            save->dda_config           = info->SavedReg.dda_config;
4291c582b7e3Smrg            save->dda_on_off           = info->SavedReg.dda_on_off;
4292c582b7e3Smrg        }
4293c582b7e3Smrg        /* not used for now */
4294c582b7e3Smrg        /*if (!info->PaletteSavedOnVT) RADEONInitPalette(save);*/
4295c582b7e3Smrg    }
4296c582b7e3Smrg
4297c582b7e3Smrg    if (((info->DisplayType == MT_DFP) ||
4298c582b7e3Smrg        (info->DisplayType == MT_LCD)))
4299c582b7e3Smrg    {
4300c582b7e3Smrg        R128InitFPRegisters(&info->SavedReg, save, mode, info);
4301c582b7e3Smrg    }
4302c582b7e3Smrg
4303c582b7e3Smrg    R128TRACE(("R128Init returns %p\n", save));
4304c582b7e3Smrg    return TRUE;
4305c582b7e3Smrg}
4306c582b7e3Smrg
4307c582b7e3Smrg/* Initialize a new mode. */
4308c582b7e3Smrgstatic Bool R128ModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
4309c582b7e3Smrg{
4310c582b7e3Smrg    R128InfoPtr info      = R128PTR(pScrn);
4311c582b7e3Smrg
4312c582b7e3Smrg    if (!R128Init(pScrn, mode, &info->ModeReg)) return FALSE;
4313c582b7e3Smrg				/* FIXME?  DRILock/DRIUnlock here? */
4314c582b7e3Smrg    pScrn->vtSema = TRUE;
4315c582b7e3Smrg    R128Blank(pScrn);
4316c582b7e3Smrg    R128RestoreMode(pScrn, &info->ModeReg);
4317c582b7e3Smrg    R128Unblank(pScrn);
4318c582b7e3Smrg
4319c582b7e3Smrg    info->CurrentLayout.mode = mode;
4320c582b7e3Smrg
4321c582b7e3Smrg    return TRUE;
4322c582b7e3Smrg}
4323c582b7e3Smrg
4324c582b7e3Smrgstatic Bool R128SaveScreen(ScreenPtr pScreen, int mode)
4325c582b7e3Smrg{
432684354367Smrg    ScrnInfoPtr   pScrn = xf86ScreenToScrn(pScreen);
4327c582b7e3Smrg    Bool unblank;
4328c582b7e3Smrg
4329c582b7e3Smrg    unblank = xf86IsUnblank(mode);
4330c582b7e3Smrg    if (unblank)
4331c582b7e3Smrg	SetTimeSinceLastInputEvent();
4332c582b7e3Smrg
4333c582b7e3Smrg    if ((pScrn != NULL) && pScrn->vtSema) {
4334c582b7e3Smrg	if (unblank)
4335c582b7e3Smrg		R128Unblank(pScrn);
4336c582b7e3Smrg	else
4337c582b7e3Smrg		R128Blank(pScrn);
4338c582b7e3Smrg    }
4339c582b7e3Smrg    return TRUE;
4340c582b7e3Smrg}
4341c582b7e3Smrg
4342c582b7e3Smrg/*
4343c582b7e3Smrg * SwitchMode() doesn't work right on crtc2 on some laptops.
4344c582b7e3Smrg * The workaround is to switch the mode, then switch to another VT, then
4345c582b7e3Smrg * switch back. --AGD
4346c582b7e3Smrg */
434784354367SmrgBool R128SwitchMode(SWITCH_MODE_ARGS_DECL)
4348c582b7e3Smrg{
434984354367Smrg    SCRN_INFO_PTR(arg);
4350c582b7e3Smrg    R128InfoPtr info        = R128PTR(pScrn);
4351c582b7e3Smrg    Bool ret;
4352c582b7e3Smrg
4353c582b7e3Smrg    info->SwitchingMode = TRUE;
435484354367Smrg    ret = R128ModeInit(pScrn, mode);
4355c582b7e3Smrg    info->SwitchingMode = FALSE;
4356c582b7e3Smrg    return ret;
4357c582b7e3Smrg}
4358c582b7e3Smrg
4359c582b7e3Smrg/* Used to disallow modes that are not supported by the hardware. */
436084354367SmrgModeStatus R128ValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode,
4361c582b7e3Smrg                                   Bool verbose, int flags)
4362c582b7e3Smrg{
436384354367Smrg    SCRN_INFO_PTR(arg);
4364c582b7e3Smrg    R128InfoPtr   info  = R128PTR(pScrn);
4365c582b7e3Smrg
4366c582b7e3Smrg    if (info->BIOSDisplay == R128_BIOS_DISPLAY_CRT)
4367c582b7e3Smrg	return MODE_OK;
4368c582b7e3Smrg
4369c582b7e3Smrg    if(info->isDFP) {
4370c582b7e3Smrg        if(info->PanelXRes < mode->CrtcHDisplay ||
4371c582b7e3Smrg           info->PanelYRes < mode->CrtcVDisplay)
4372c582b7e3Smrg            return MODE_NOMODE;
4373c582b7e3Smrg        else
4374c582b7e3Smrg            return MODE_OK;
4375c582b7e3Smrg    }
4376c582b7e3Smrg
4377c582b7e3Smrg    if (info->DisplayType == MT_LCD) {
4378c582b7e3Smrg	if (mode->Flags & V_INTERLACE) return MODE_NO_INTERLACE;
4379c582b7e3Smrg	if (mode->Flags & V_DBLSCAN)   return MODE_NO_DBLESCAN;
4380c582b7e3Smrg    }
4381c582b7e3Smrg
4382c582b7e3Smrg    if (info->DisplayType == MT_LCD &&
4383c582b7e3Smrg	info->VBIOS) {
4384c582b7e3Smrg	int i;
4385c582b7e3Smrg	for (i = info->FPBIOSstart+64; R128_BIOS16(i) != 0; i += 2) {
4386c582b7e3Smrg	    int j = R128_BIOS16(i);
4387c582b7e3Smrg
4388c582b7e3Smrg	    if (mode->CrtcHDisplay == R128_BIOS16(j) &&
4389c582b7e3Smrg		mode->CrtcVDisplay == R128_BIOS16(j+2)) {
4390c582b7e3Smrg		if ((flags & MODECHECK_FINAL) == MODECHECK_FINAL) {
4391c582b7e3Smrg		    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4392c582b7e3Smrg			       "Modifying mode according to VBIOS: %ix%i [pclk %.1f MHz] for FP to: ",
4393c582b7e3Smrg			       mode->CrtcHDisplay,mode->CrtcVDisplay,
4394c582b7e3Smrg			       (float)mode->Clock/1000);
4395c582b7e3Smrg
4396c582b7e3Smrg		    /* Assume we are using expanded mode */
4397c582b7e3Smrg		    if (R128_BIOS16(j+5)) j  = R128_BIOS16(j+5);
4398c582b7e3Smrg		    else                  j += 9;
4399c582b7e3Smrg
4400c582b7e3Smrg		    mode->Clock = (CARD32)R128_BIOS16(j) * 10;
4401c582b7e3Smrg
4402c582b7e3Smrg		    mode->HDisplay   = mode->CrtcHDisplay   =
4403c582b7e3Smrg			((R128_BIOS16(j+10) & 0x01ff)+1)*8;
4404c582b7e3Smrg		    mode->HSyncStart = mode->CrtcHSyncStart =
4405c582b7e3Smrg			((R128_BIOS16(j+12) & 0x01ff)+1)*8;
4406c582b7e3Smrg		    mode->HSyncEnd   = mode->CrtcHSyncEnd   =
4407c582b7e3Smrg			mode->CrtcHSyncStart + (R128_BIOS8(j+14) & 0x1f);
4408c582b7e3Smrg		    mode->HTotal     = mode->CrtcHTotal     =
4409c582b7e3Smrg			((R128_BIOS16(j+8)  & 0x01ff)+1)*8;
4410c582b7e3Smrg
4411c582b7e3Smrg		    mode->VDisplay   = mode->CrtcVDisplay   =
4412c582b7e3Smrg			(R128_BIOS16(j+17) & 0x07ff)+1;
4413c582b7e3Smrg		    mode->VSyncStart = mode->CrtcVSyncStart =
4414c582b7e3Smrg			(R128_BIOS16(j+19) & 0x07ff)+1;
4415c582b7e3Smrg		    mode->VSyncEnd   = mode->CrtcVSyncEnd   =
4416c582b7e3Smrg			mode->CrtcVSyncStart + ((R128_BIOS16(j+19) >> 11) & 0x1f);
4417c582b7e3Smrg		    mode->VTotal     = mode->CrtcVTotal     =
4418c582b7e3Smrg			(R128_BIOS16(j+15) & 0x07ff)+1;
4419c582b7e3Smrg		    xf86ErrorF("%ix%i [pclk %.1f MHz]\n",
4420c582b7e3Smrg			       mode->CrtcHDisplay,mode->CrtcVDisplay,
4421c582b7e3Smrg			       (float)mode->Clock/1000);
4422c582b7e3Smrg		}
4423c582b7e3Smrg		return MODE_OK;
4424c582b7e3Smrg	    }
4425c582b7e3Smrg	}
4426c582b7e3Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 5,
4427c582b7e3Smrg		       "Mode rejected for FP %ix%i [pclk: %.1f] "
4428c582b7e3Smrg		       "(not listed in VBIOS)\n",
4429c582b7e3Smrg		       mode->CrtcHDisplay, mode->CrtcVDisplay,
4430c582b7e3Smrg		       (float)mode->Clock / 1000);
4431c582b7e3Smrg	return MODE_NOMODE;
4432c582b7e3Smrg    }
4433c582b7e3Smrg
4434c582b7e3Smrg    return MODE_OK;
4435c582b7e3Smrg}
4436c582b7e3Smrg
4437c582b7e3Smrg/* Adjust viewport into virtual desktop such that (0,0) in viewport space
4438c582b7e3Smrg   is (x,y) in virtual space. */
443984354367Smrgvoid R128AdjustFrame(ADJUST_FRAME_ARGS_DECL)
4440c582b7e3Smrg{
444184354367Smrg    SCRN_INFO_PTR(arg);
4442c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
4443c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
4444c582b7e3Smrg    int           Base;
4445c582b7e3Smrg
4446c582b7e3Smrg    if(info->showCache && y && pScrn->vtSema)
4447c582b7e3Smrg        y += pScrn->virtualY - 1;
4448c582b7e3Smrg
4449c582b7e3Smrg    Base = y * info->CurrentLayout.displayWidth + x;
4450c582b7e3Smrg
4451c582b7e3Smrg    switch (info->CurrentLayout.pixel_code) {
4452c582b7e3Smrg    case 15:
4453c582b7e3Smrg    case 16: Base *= 2; break;
4454c582b7e3Smrg    case 24: Base *= 3; break;
4455c582b7e3Smrg    case 32: Base *= 4; break;
4456c582b7e3Smrg    }
4457c582b7e3Smrg
4458c582b7e3Smrg    Base &= ~7;                 /* 3 lower bits are always 0 */
4459c582b7e3Smrg
4460c582b7e3Smrg    if (info->CurrentLayout.pixel_code == 24)
4461c582b7e3Smrg	Base += 8 * (Base % 3); /* Must be multiple of 8 and 3 */
4462c582b7e3Smrg
4463c582b7e3Smrg    if(info->IsSecondary)
4464c582b7e3Smrg    {
4465c582b7e3Smrg        Base += pScrn->fbOffset;
4466c582b7e3Smrg        OUTREG(R128_CRTC2_OFFSET, Base);
4467c582b7e3Smrg    }
4468c582b7e3Smrg    else
4469c582b7e3Smrg    OUTREG(R128_CRTC_OFFSET, Base);
4470c582b7e3Smrg
4471c582b7e3Smrg}
4472c582b7e3Smrg
4473c582b7e3Smrg/* Called when VT switching back to the X server.  Reinitialize the video
4474c582b7e3Smrg   mode. */
447584354367SmrgBool R128EnterVT(VT_FUNC_ARGS_DECL)
4476c582b7e3Smrg{
447784354367Smrg    SCRN_INFO_PTR(arg);
4478c582b7e3Smrg    R128InfoPtr info  = R128PTR(pScrn);
4479c582b7e3Smrg
4480c582b7e3Smrg    R128TRACE(("R128EnterVT\n"));
448179e5230eSmacallan#ifndef AVOID_FBDEV
4482c582b7e3Smrg    if (info->FBDev) {
448384354367Smrg        if (!fbdevHWEnterVT(VT_FUNC_ARGS)) return FALSE;
4484c582b7e3Smrg    } else
448579e5230eSmacallan#endif
4486c582b7e3Smrg        if (!R128ModeInit(pScrn, pScrn->currentMode)) return FALSE;
4487c582b7e3Smrg    if (info->accelOn)
4488c582b7e3Smrg	R128EngineInit(pScrn);
4489c582b7e3Smrg
449084354367Smrg#ifdef R128DRI
4491c582b7e3Smrg    if (info->directRenderingEnabled) {
4492c582b7e3Smrg	if (info->irq) {
4493c582b7e3Smrg	    /* Need to make sure interrupts are enabled */
4494c582b7e3Smrg	    unsigned char *R128MMIO = info->MMIO;
4495c582b7e3Smrg	    OUTREG(R128_GEN_INT_CNTL, info->gen_int_cntl);
4496c582b7e3Smrg	}
4497c582b7e3Smrg	R128CCE_START(pScrn, info);
4498c582b7e3Smrg	DRIUnlock(pScrn->pScreen);
4499c582b7e3Smrg    }
4500c582b7e3Smrg#endif
4501c582b7e3Smrg
4502c582b7e3Smrg    info->PaletteSavedOnVT = FALSE;
450384354367Smrg    pScrn->AdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
4504c582b7e3Smrg
4505c582b7e3Smrg    return TRUE;
4506c582b7e3Smrg}
4507c582b7e3Smrg
4508c582b7e3Smrg/* Called when VT switching away from the X server.  Restore the original
4509c582b7e3Smrg   text mode. */
451084354367Smrgvoid R128LeaveVT(VT_FUNC_ARGS_DECL)
4511c582b7e3Smrg{
451284354367Smrg    SCRN_INFO_PTR(arg);
4513c582b7e3Smrg    R128InfoPtr info  = R128PTR(pScrn);
4514c582b7e3Smrg    R128SavePtr save  = &info->ModeReg;
4515c582b7e3Smrg
4516c582b7e3Smrg    R128TRACE(("R128LeaveVT\n"));
451784354367Smrg#ifdef R128DRI
4518c582b7e3Smrg    if (info->directRenderingEnabled) {
4519c582b7e3Smrg	DRILock(pScrn->pScreen, 0);
4520c582b7e3Smrg	R128CCE_STOP(pScrn, info);
4521c582b7e3Smrg    }
452284354367Smrg#ifdef USE_EXA
452384354367Smrg    if (info->useEXA)
452484354367Smrg        info->state_2d.composite_setup = FALSE;
452584354367Smrg#endif
4526c582b7e3Smrg#endif
4527c582b7e3Smrg    R128SavePalette(pScrn, save);
4528c582b7e3Smrg    info->PaletteSavedOnVT = TRUE;
452979e5230eSmacallan#ifndef AVOID_FBDEV
4530c582b7e3Smrg    if (info->FBDev)
453184354367Smrg        fbdevHWLeaveVT(VT_FUNC_ARGS);
4532c582b7e3Smrg    else
453379e5230eSmacallan#endif
4534c582b7e3Smrg        R128Restore(pScrn);
4535c582b7e3Smrg}
4536c582b7e3Smrg
4537c582b7e3Smrg
4538c582b7e3Smrg/* Called at the end of each server generation.  Restore the original text
4539c582b7e3Smrg   mode, unmap video memory, and unwrap and call the saved CloseScreen
4540c582b7e3Smrg   function.  */
454184354367Smrgstatic Bool R128CloseScreen(CLOSE_SCREEN_ARGS_DECL)
4542c582b7e3Smrg{
454384354367Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
4544c582b7e3Smrg    R128InfoPtr info  = R128PTR(pScrn);
4545c582b7e3Smrg
4546c582b7e3Smrg    R128TRACE(("R128CloseScreen\n"));
4547c582b7e3Smrg
454884354367Smrg#ifdef R128DRI
4549c582b7e3Smrg				/* Disable direct rendering */
4550c582b7e3Smrg    if (info->directRenderingEnabled) {
4551c582b7e3Smrg	R128DRICloseScreen(pScreen);
4552c582b7e3Smrg	info->directRenderingEnabled = FALSE;
4553c582b7e3Smrg    }
4554c582b7e3Smrg#endif
4555c582b7e3Smrg
4556c582b7e3Smrg    if (pScrn->vtSema) {
4557c582b7e3Smrg	R128Restore(pScrn);
4558c582b7e3Smrg	R128UnmapMem(pScrn);
4559c582b7e3Smrg    }
4560c582b7e3Smrg
456184354367Smrg#ifdef USE_EXA
456284354367Smrg        if (info->useEXA) {
456384354367Smrg	    exaDriverFini(pScreen);
456484354367Smrg	    free(info->ExaDriver);
456584354367Smrg	} else
456684354367Smrg#endif
456784354367Smrg#ifdef HAVE_XAA_H
456884354367Smrg	{
456984354367Smrg            if (info->accel)             XAADestroyInfoRec(info->accel);
457084354367Smrg	    info->accel                  = NULL;
457184354367Smrg        }
457284354367Smrg#endif
4573c582b7e3Smrg
457484354367Smrg    if (info->scratch_save)      free(info->scratch_save);
4575c582b7e3Smrg    info->scratch_save           = NULL;
4576c582b7e3Smrg
4577c582b7e3Smrg    if (info->cursor)            xf86DestroyCursorInfoRec(info->cursor);
4578c582b7e3Smrg    info->cursor                 = NULL;
4579c582b7e3Smrg
458084354367Smrg    if (info->DGAModes)          free(info->DGAModes);
4581c582b7e3Smrg    info->DGAModes               = NULL;
4582c582b7e3Smrg
4583c582b7e3Smrg    if (info->adaptor) {
458484354367Smrg        free(info->adaptor->pPortPrivates[0].ptr);
4585c582b7e3Smrg	xf86XVFreeVideoAdaptorRec(info->adaptor);
4586c582b7e3Smrg	info->adaptor = NULL;
4587c582b7e3Smrg    }
4588c582b7e3Smrg
4589c582b7e3Smrg    pScrn->vtSema = FALSE;
4590c582b7e3Smrg
4591c582b7e3Smrg    pScreen->BlockHandler = info->BlockHandler;
4592c582b7e3Smrg    pScreen->CloseScreen = info->CloseScreen;
459384354367Smrg    return (*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS);
4594c582b7e3Smrg}
4595c582b7e3Smrg
459684354367Smrgvoid R128FreeScreen(FREE_SCREEN_ARGS_DECL)
4597c582b7e3Smrg{
459884354367Smrg    SCRN_INFO_PTR(arg);
4599c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
4600c582b7e3Smrg
4601c582b7e3Smrg    R128TRACE(("R128FreeScreen\n"));
460219019ffeSmrg    if (info == NULL)
460319019ffeSmrg	return;
4604c582b7e3Smrg#ifdef WITH_VGAHW
4605c582b7e3Smrg    if (info->VGAAccess && xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
4606c582b7e3Smrg	vgaHWFreeHWRec(pScrn);
4607c582b7e3Smrg#endif
4608c582b7e3Smrg    R128FreeRec(pScrn);
4609c582b7e3Smrg}
4610c582b7e3Smrg
4611c582b7e3Smrg/* Sets VESA Display Power Management Signaling (DPMS) Mode.  */
4612c582b7e3Smrgstatic void R128DisplayPowerManagementSet(ScrnInfoPtr pScrn,
4613c582b7e3Smrg					  int PowerManagementMode, int flags)
4614c582b7e3Smrg{
4615c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
4616c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
4617c582b7e3Smrg    int           mask      = (R128_CRTC_DISPLAY_DIS
4618c582b7e3Smrg			       | R128_CRTC_HSYNC_DIS
4619c582b7e3Smrg			       | R128_CRTC_VSYNC_DIS);
4620c582b7e3Smrg    int             mask2     = R128_CRTC2_DISP_DIS;
4621c582b7e3Smrg
4622c582b7e3Smrg    switch (PowerManagementMode) {
4623c582b7e3Smrg    case DPMSModeOn:
4624c582b7e3Smrg	/* Screen: On; HSync: On, VSync: On */
4625c582b7e3Smrg	if (info->IsSecondary)
4626c582b7e3Smrg		OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~mask2);
4627c582b7e3Smrg	else
4628c582b7e3Smrg		OUTREGP(R128_CRTC_EXT_CNTL, 0, ~mask);
4629c582b7e3Smrg	break;
4630c582b7e3Smrg    case DPMSModeStandby:
4631c582b7e3Smrg	/* Screen: Off; HSync: Off, VSync: On */
4632c582b7e3Smrg	if (info->IsSecondary)
4633c582b7e3Smrg		OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask2);
4634c582b7e3Smrg	    else
4635c582b7e3Smrg		OUTREGP(R128_CRTC_EXT_CNTL,
4636c582b7e3Smrg			R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS, ~mask);
4637c582b7e3Smrg	break;
4638c582b7e3Smrg    case DPMSModeSuspend:
4639c582b7e3Smrg	/* Screen: Off; HSync: On, VSync: Off */
4640c582b7e3Smrg	if (info->IsSecondary)
4641c582b7e3Smrg		OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~mask2);
4642c582b7e3Smrg	else
4643c582b7e3Smrg		OUTREGP(R128_CRTC_EXT_CNTL,
4644c582b7e3Smrg			R128_CRTC_DISPLAY_DIS | R128_CRTC_VSYNC_DIS, ~mask);
4645c582b7e3Smrg	break;
4646c582b7e3Smrg    case DPMSModeOff:
4647c582b7e3Smrg	/* Screen: Off; HSync: Off, VSync: Off */
4648c582b7e3Smrg	if (info->IsSecondary)
4649c582b7e3Smrg		OUTREGP(R128_CRTC2_GEN_CNTL, mask2, ~mask2);
4650c582b7e3Smrg	else
4651c582b7e3Smrg		OUTREGP(R128_CRTC_EXT_CNTL, mask, ~mask);
4652c582b7e3Smrg	break;
4653c582b7e3Smrg    }
4654c582b7e3Smrg    if(info->isDFP) {
4655c582b7e3Smrg	switch (PowerManagementMode) {
4656c582b7e3Smrg	case DPMSModeOn:
4657c582b7e3Smrg	    OUTREG(R128_FP_GEN_CNTL, INREG(R128_FP_GEN_CNTL) | (R128_FP_FPON | R128_FP_TDMS_EN));
4658c582b7e3Smrg	    break;
4659c582b7e3Smrg	case DPMSModeStandby:
4660c582b7e3Smrg	case DPMSModeSuspend:
4661c582b7e3Smrg	case DPMSModeOff:
4662c582b7e3Smrg	    OUTREG(R128_FP_GEN_CNTL, INREG(R128_FP_GEN_CNTL) & ~(R128_FP_FPON | R128_FP_TDMS_EN));
4663c582b7e3Smrg	    break;
4664c582b7e3Smrg	}
4665c582b7e3Smrg    }
4666c582b7e3Smrg}
4667c582b7e3Smrg
4668c582b7e3Smrgstatic int r128_set_backlight_enable(ScrnInfoPtr pScrn, int on);
4669c582b7e3Smrg
4670c582b7e3Smrgstatic void R128DisplayPowerManagementSetLCD(ScrnInfoPtr pScrn,
4671c582b7e3Smrg					  int PowerManagementMode, int flags)
4672c582b7e3Smrg{
4673c582b7e3Smrg    R128InfoPtr   info      = R128PTR(pScrn);
4674c582b7e3Smrg    unsigned char *R128MMIO = info->MMIO;
4675c582b7e3Smrg    int           mask      = R128_LVDS_DISPLAY_DIS;
4676c582b7e3Smrg
4677c582b7e3Smrg    switch (PowerManagementMode) {
4678c582b7e3Smrg    case DPMSModeOn:
4679c582b7e3Smrg	/* Screen: On; HSync: On, VSync: On */
4680c582b7e3Smrg	OUTREGP(R128_LVDS_GEN_CNTL, 0, ~mask);
4681c582b7e3Smrg        r128_set_backlight_enable(pScrn, 1);
4682c582b7e3Smrg	break;
4683c582b7e3Smrg    case DPMSModeStandby:
4684c582b7e3Smrg	/* Fall through */
4685c582b7e3Smrg    case DPMSModeSuspend:
4686c582b7e3Smrg	/* Fall through */
4687c582b7e3Smrg    case DPMSModeOff:
4688c582b7e3Smrg	/* Screen: Off; HSync: Off, VSync: Off */
4689c582b7e3Smrg	OUTREGP(R128_LVDS_GEN_CNTL, mask, ~mask);
4690c582b7e3Smrg        r128_set_backlight_enable(pScrn, 0);
4691c582b7e3Smrg	break;
4692c582b7e3Smrg    }
4693c582b7e3Smrg}
4694c582b7e3Smrg
4695c582b7e3Smrgstatic int r128_set_backlight_enable(ScrnInfoPtr pScrn, int on)
4696c582b7e3Smrg{
4697c582b7e3Smrg        R128InfoPtr info        = R128PTR(pScrn);
4698c582b7e3Smrg        unsigned char *R128MMIO = info->MMIO;
4699c582b7e3Smrg	unsigned int lvds_gen_cntl = INREG(R128_LVDS_GEN_CNTL);
4700c582b7e3Smrg
4701c582b7e3Smrg	lvds_gen_cntl |= (/*R128_LVDS_BL_MOD_EN |*/ R128_LVDS_BLON);
4702c582b7e3Smrg	if (on) {
4703c582b7e3Smrg		lvds_gen_cntl |= R128_LVDS_DIGON;
4704c582b7e3Smrg		if (!(lvds_gen_cntl & R128_LVDS_ON)) {
4705c582b7e3Smrg			lvds_gen_cntl &= ~R128_LVDS_BLON;
4706c582b7e3Smrg			OUTREG(R128_LVDS_GEN_CNTL, lvds_gen_cntl);
4707c582b7e3Smrg			(void)INREG(R128_LVDS_GEN_CNTL);
4708c582b7e3Smrg			usleep(10000);
4709c582b7e3Smrg			lvds_gen_cntl |= R128_LVDS_BLON;
4710c582b7e3Smrg			OUTREG(R128_LVDS_GEN_CNTL, lvds_gen_cntl);
4711c582b7e3Smrg		}
4712c582b7e3Smrg#if 0
4713c582b7e3Smrg		lvds_gen_cntl &= ~R128_LVDS_BL_MOD_LEVEL_MASK;
4714c582b7e3Smrg		lvds_gen_cntl |= (0xFF /* backlight_conv[level] */ <<
4715c582b7e3Smrg				  R128_LVDS_BL_MOD_LEVEL_SHIFT);
4716c582b7e3Smrg#endif
4717c582b7e3Smrg		lvds_gen_cntl |= (R128_LVDS_ON | R128_LVDS_EN);
4718c582b7e3Smrg		lvds_gen_cntl &= ~R128_LVDS_DISPLAY_DIS;
4719c582b7e3Smrg	} else {
4720c582b7e3Smrg#if 0
4721c582b7e3Smrg		lvds_gen_cntl &= ~R128_LVDS_BL_MOD_LEVEL_MASK;
4722c582b7e3Smrg		lvds_gen_cntl |= (0xFF /* backlight_conv[0] */ <<
4723c582b7e3Smrg				  R128_LVDS_BL_MOD_LEVEL_SHIFT);
4724c582b7e3Smrg#endif
4725c582b7e3Smrg		lvds_gen_cntl |= R128_LVDS_DISPLAY_DIS;
4726c582b7e3Smrg		OUTREG(R128_LVDS_GEN_CNTL, lvds_gen_cntl);
4727c582b7e3Smrg		usleep(10);
4728c582b7e3Smrg		lvds_gen_cntl &= ~(R128_LVDS_ON | R128_LVDS_EN | R128_LVDS_BLON
4729c582b7e3Smrg				   | R128_LVDS_DIGON);
4730c582b7e3Smrg	}
4731c582b7e3Smrg
4732c582b7e3Smrg	OUTREG(R128_LVDS_GEN_CNTL, lvds_gen_cntl);
4733c582b7e3Smrg
4734c582b7e3Smrg	return 0;
4735c582b7e3Smrg}
4736