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