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