176888252Smrg/*
276888252Smrg * Driver for CL-GD546x -- The Laguna family
376888252Smrg *
476888252Smrg * lg_driver.c
576888252Smrg *
676888252Smrg * (c) 1998 Corin Anderson.
776888252Smrg *          corina@the4cs.com
876888252Smrg *          Tukwila, WA
976888252Smrg *
1076888252Smrg * This driver is derived from the cir_driver.c module.
1176888252Smrg * Original authors and contributors list include:
12d2b10af6Smrg *      Radoslaw Kapitan, Andrew Vanderstock, Dirk Hohndel,
13d2b10af6Smrg *      David Dawes, Andrew E. Mileski, Leonard N. Zubkoff,
14d2b10af6Smrg *      Guy DESBIEF, Itai Nahshon.
1576888252Smrg */
1676888252Smrg
1776888252Smrg#ifdef HAVE_CONFIG_H
1876888252Smrg#include "config.h"
1976888252Smrg#endif
2076888252Smrg
2176888252Smrg#define EXPERIMENTAL
2276888252Smrg
23d2b10af6Smrg/*
24d2b10af6Smrg * All drivers should typically include these.
25d2b10af6Smrg */
2676888252Smrg#include "xf86.h"
2776888252Smrg#include "xf86_OSproc.h"
2876888252Smrg
29d2b10af6Smrg/*
30d2b10af6Smrg * All drivers need this.
31d2b10af6Smrg */
3276888252Smrg
3376888252Smrg#include "compiler.h"
3476888252Smrg
35d2b10af6Smrg/*
36d2b10af6Smrg * Drivers that need to access the PCI config space directly need
37d2b10af6Smrg * this.
38d2b10af6Smrg */
3976888252Smrg#include "xf86Pci.h"
4076888252Smrg
41d2b10af6Smrg/*
42d2b10af6Smrg * All drivers using the vgahw module need this.  This driver needs
43d2b10af6Smrg * to be modified to not use vgaHW for multihead operation.
44d2b10af6Smrg */
4576888252Smrg#include "vgaHW.h"
4676888252Smrg
471e66b2a2Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6
4876888252Smrg#include "xf86RAC.h"
4976888252Smrg#include "xf86Resources.h"
501e66b2a2Smrg#endif
5176888252Smrg
52d2b10af6Smrg/*
53d2b10af6Smrg * All drivers initialising the SW cursor need this.
54d2b10af6Smrg */
5576888252Smrg#include "mipointer.h"
5676888252Smrg
57d2b10af6Smrg/*
58d2b10af6Smrg * Need this for inputInfo.
59d2b10af6Smrg */
60afee0becSmrg#include "inputstr.h"
61afee0becSmrg
6276888252Smrg#include "micmap.h"
6376888252Smrg
64d2b10af6Smrg/*
65d2b10af6Smrg * Needed by the shadowfb.
66d2b10af6Smrg */
6776888252Smrg#include "shadowfb.h"
6876888252Smrg
6976888252Smrg#include "xf86int10.h"
7076888252Smrg
7176888252Smrg#include "fb.h"
7276888252Smrg
7376888252Smrg#include "xf86DDC.h"
7476888252Smrg
7576888252Smrg#undef LG_DEBUG
7676888252Smrg
7776888252Smrg#include "cir.h"
7876888252Smrg#define _LG_PRIVATE_
7976888252Smrg#include "lg.h"
8076888252Smrg
8176888252Smrg#include "xf86xv.h"
8276888252Smrg#include <X11/extensions/Xv.h>
8376888252Smrg
8476888252Smrg/*
8576888252Smrg * Forward definitions for the functions that make up the driver.
8676888252Smrg */
8776888252Smrg
88d2b10af6Smrg/*
89d2b10af6Smrg * Mandatory functions
90d2b10af6Smrg */
9176888252SmrgBool LgPreInit(ScrnInfoPtr pScrn, int flags);
925c69f917SmrgBool LgScreenInit(SCREEN_INIT_ARGS_DECL);
935c69f917SmrgBool LgEnterVT(VT_FUNC_ARGS_DECL);
945c69f917Smrgvoid LgLeaveVT(VT_FUNC_ARGS_DECL);
95d2b10af6Smrgstatic Bool LgCloseScreen(CLOSE_SCREEN_ARGS_DECL);
96d2b10af6Smrgstatic Bool LgSaveScreen(ScreenPtr pScreen, Bool mode);
9776888252Smrg
98d2b10af6Smrg/*
99d2b10af6Smrg * Required if the driver supports mode switching.
100d2b10af6Smrg */
1015c69f917SmrgBool LgSwitchMode(SWITCH_MODE_ARGS_DECL);
102d2b10af6Smrg/*
103d2b10af6Smrg * Required if the driver supports moving the viewport.
104d2b10af6Smrg */
1055c69f917Smrgvoid LgAdjustFrame(ADJUST_FRAME_ARGS_DECL);
10676888252Smrg
107d2b10af6Smrg/*
108d2b10af6Smrg * Optional functions
109d2b10af6Smrg */
1105c69f917Smrgvoid LgFreeScreen(FREE_SCREEN_ARGS_DECL);
1115c69f917SmrgModeStatus LgValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode,
112d2b10af6Smrg                        Bool verbose, int flags);
11376888252Smrg
114d2b10af6Smrg/*
115d2b10af6Smrg * Internal functions
116d2b10af6Smrg */
11776888252Smrgstatic void LgRestoreLgRegs(ScrnInfoPtr pScrn, LgRegPtr lgReg);
11876888252Smrgstatic int LgFindLineData(int displayWidth, int bpp);
11976888252Smrgstatic CARD16 LgSetClock(CirPtr pCir, vgaHWPtr hwp, int freq);
12076888252Smrgstatic void lg_vgaHWSetMmioFunc(vgaHWPtr hwp, CARD8 *base);
12176888252Smrg
12276888252Smrgstatic void LgDisplayPowerManagementSet(ScrnInfoPtr pScrn,
123d2b10af6Smrg                                        int PowerManagementMode,
124d2b10af6Smrg                                        int flags);
12576888252Smrg
12676888252Smrg/*
12776888252Smrg * This is intentionally screen-independent.  It indicates the binding
12876888252Smrg * choice made in the first PreInit.
12976888252Smrg */
13076888252Smrgstatic int pix24bpp = 0;
13176888252Smrg
13276888252Smrg/*
13376888252Smrg * This contains the functions needed by the server after loading the
134d2b10af6Smrg * driver module.  It must be supplied, and gets added the driver list
135d2b10af6Smrg * by the Module Setup function in the dynamic case.  In the static
136d2b10af6Smrg * case a reference to this is compiled in, and this requires that the
137d2b10af6Smrg * name of this DriverRec be an upper-case version of the driver name.
13876888252Smrg */
13976888252Smrg
14076888252Smrgtypedef enum {
141d2b10af6Smrg    OPTION_HW_CURSOR,
142d2b10af6Smrg    OPTION_PCI_RETRY,
143d2b10af6Smrg    OPTION_ROTATE,
144d2b10af6Smrg    OPTION_SHADOW_FB,
145d2b10af6Smrg    OPTION_NOACCEL
14676888252Smrg} LgOpts;
14776888252Smrg
14876888252Smrgstatic const OptionInfoRec LgOptions[] = {
149d2b10af6Smrg    { OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN,   {0},    FALSE },
150d2b10af6Smrg    { OPTION_NOACCEL,   "NoAccel",  OPTV_BOOLEAN,   {0},    FALSE },
151d2b10af6Smrg    { OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN,   {0},    FALSE },
152d2b10af6Smrg    { OPTION_ROTATE,    "Rotate",   OPTV_ANYSTR,    {0},    FALSE },
153d2b10af6Smrg/*
154d2b10af6Smrg * fifo_conservative/aggressive; fast/med/slow_dram; ...
155d2b10af6Smrg */
156d2b10af6Smrg    { -1,               NULL,       OPTV_NONE,      {0},    FALSE }
15776888252Smrg};
15876888252Smrg
159d2b10af6Smrg/*
160d2b10af6Smrg *                       1/4 bpp  8 bpp 15/16 bpp 24 bpp  32 bpp
161d2b10af6Smrg */
162d2b10af6Smrgstatic int gd5462_MaxClocks[] =
163d2b10af6Smrg                        { 170000, 170000, 135100, 135100,  85500 };
164d2b10af6Smrgstatic int gd5464_MaxClocks[] =
165d2b10af6Smrg                        { 170000, 250000, 170000, 170000, 135100 };
166d2b10af6Smrgstatic int gd5465_MaxClocks[] =
167d2b10af6Smrg                        { 170000, 250000, 170000, 170000, 135100 };
16876888252Smrg
169d2b10af6Smrg/*
170d2b10af6Smrg * We're rather use skinny tiles, so put all of them at the head of
171d2b10af6Smrg * the table.
172d2b10af6Smrg */
17376888252SmrgLgLineDataRec LgLineData[] = {
174d2b10af6Smrg    { 5,  640, 0},
175d2b10af6Smrg    { 8, 1024, 0},
176d2b10af6Smrg    {10, 1280, 0},
177d2b10af6Smrg    {13, 1664, 0},
178d2b10af6Smrg    {16, 2048, 0},
179d2b10af6Smrg    {20, 2560, 0},
180d2b10af6Smrg    {10, 2560, 1},
181d2b10af6Smrg    {26, 3328, 0},
182d2b10af6Smrg    { 5, 1280, 1},
183d2b10af6Smrg    { 8, 2048, 1},
184d2b10af6Smrg    {13, 3328, 1},
185d2b10af6Smrg    {16, 4096, 1},
186d2b10af6Smrg    {20, 5120, 1},
187d2b10af6Smrg    {26, 6656, 1},
188d2b10af6Smrg/*
189d2b10af6Smrg * Sentinel to indicate end of table.
190d2b10af6Smrg */
191d2b10af6Smrg    {-1, -1,   -1}
19276888252Smrg};
19376888252Smrg
19476888252Smrgstatic int LgLinePitches[4][11] = {
195d2b10af6Smrg/*
196d2b10af6Smrg *  8 bpp
197d2b10af6Smrg */
198d2b10af6Smrg    { 640, 1024, 1280, 1664, 2048, 2560, 3328, 4096, 5120, 6656, 0 },
199d2b10af6Smrg/*
200d2b10af6Smrg * 16 bpp
201d2b10af6Smrg */
202d2b10af6Smrg    { 320,  512,  640,  832, 1024, 1280, 1664, 2048, 2560, 3328, 0 },
203d2b10af6Smrg/*
204d2b10af6Smrg * 24 bpp
205d2b10af6Smrg */
206d2b10af6Smrg    { 213,  341,  426,  554,  682,  853, 1109, 1365, 1706, 2218, 0 },
207d2b10af6Smrg/*
208d2b10af6Smrg * 32 bpp
209d2b10af6Smrg */
210d2b10af6Smrg    { 160,  256,  320,  416,  512,  640,  832, 1024, 1280, 1664, 0 }
21176888252Smrg};
21276888252Smrg
21376888252Smrg#ifdef XFree86LOADER
21476888252Smrg
21576888252Smrg#define LG_MAJOR_VERSION 1
21676888252Smrg#define LG_MINOR_VERSION 0
21776888252Smrg#define LG_PATCHLEVEL 0
21876888252Smrg
21976888252Smrgstatic XF86ModuleVersionInfo lgVersRec =
22076888252Smrg{
221d2b10af6Smrg    "cirrus_laguna",
222d2b10af6Smrg    MODULEVENDORSTRING,
223d2b10af6Smrg    MODINFOSTRING1,
224d2b10af6Smrg    MODINFOSTRING2,
225d2b10af6Smrg    XORG_VERSION_CURRENT,
226d2b10af6Smrg    LG_MAJOR_VERSION, LG_MINOR_VERSION, LG_PATCHLEVEL,
227d2b10af6Smrg/*
228d2b10af6Smrg * This is a video driver.
229d2b10af6Smrg */
230d2b10af6Smrg    ABI_CLASS_VIDEODRV,
231d2b10af6Smrg    ABI_VIDEODRV_VERSION,
232d2b10af6Smrg    MOD_CLASS_NONE,
233d2b10af6Smrg    {0,0,0,0}
23476888252Smrg};
23576888252Smrg
23676888252Smrg/*
23776888252Smrg * This is the module init data.
23876888252Smrg * Its name has to be the driver name followed by ModuleData.
23976888252Smrg */
24076888252Smrg_X_EXPORT XF86ModuleData cirrus_lagunaModuleData = {
24176888252Smrg    &lgVersRec,
242d2b10af6Smrg    NULL,
24376888252Smrg    NULL
24476888252Smrg};
24576888252Smrg
24676888252Smrg#endif /* XFree86LOADER */
24776888252Smrg
24876888252Smrg_X_EXPORT const OptionInfoRec *
249d2b10af6SmrgLgAvailableOptions(int chipid) {
25076888252Smrg    return LgOptions;
25176888252Smrg}
25276888252Smrg
25376888252Smrg_X_EXPORT ScrnInfoPtr
25476888252SmrgLgProbe(int entity)
25576888252Smrg{
25676888252Smrg    ScrnInfoPtr pScrn = NULL;
257d2b10af6Smrg    if ((pScrn = xf86ConfigPciEntity(pScrn, 0, entity,
258d2b10af6Smrg                                        CIRPciChipsets,
259d2b10af6Smrg                                        NULL, NULL, NULL,
260d2b10af6Smrg                                        NULL, NULL))) {
261d2b10af6Smrg        pScrn->PreInit = LgPreInit;
262d2b10af6Smrg        pScrn->ScreenInit = LgScreenInit;
263d2b10af6Smrg        pScrn->SwitchMode = LgSwitchMode;
264d2b10af6Smrg        pScrn->AdjustFrame = LgAdjustFrame;
265d2b10af6Smrg        pScrn->EnterVT = LgEnterVT;
266d2b10af6Smrg        pScrn->LeaveVT = LgLeaveVT;
267d2b10af6Smrg        pScrn->FreeScreen = LgFreeScreen;
268d2b10af6Smrg        pScrn->ValidMode = LgValidMode;
26976888252Smrg    }
27076888252Smrg    return pScrn;
27176888252Smrg}
27276888252Smrg
27376888252Smrgstatic Bool
27476888252SmrgLgGetRec(ScrnInfoPtr pScrn)
27576888252Smrg{
276d2b10af6Smrg    CirPtr pCir;
27776888252Smrg
278d2b10af6Smrg    if (pScrn->driverPrivate != NULL)
279d2b10af6Smrg        return TRUE;
28076888252Smrg
281d2b10af6Smrg    pScrn->driverPrivate = xnfcalloc(sizeof(CirRec), 1);
282d2b10af6Smrg    ((CirPtr) pScrn->driverPrivate)->chip.lg =
283d2b10af6Smrg                                        xnfcalloc(sizeof(LgRec), 1);
28476888252Smrg
285d2b10af6Smrg    /*
286d2b10af6Smrg     * Initialize it.
287d2b10af6Smrg     */
288d2b10af6Smrg    pCir = CIRPTR(pScrn);
289d2b10af6Smrg    pCir->chip.lg->oldBitmask = 0x00000000;
29076888252Smrg
291d2b10af6Smrg    return TRUE;
29276888252Smrg}
29376888252Smrg
29476888252Smrgstatic void
29576888252SmrgLgFreeRec(ScrnInfoPtr pScrn)
29676888252Smrg{
297d2b10af6Smrg    if (pScrn->driverPrivate == NULL)
298d2b10af6Smrg        return;
299d2b10af6Smrg    free(pScrn->driverPrivate);
300d2b10af6Smrg    pScrn->driverPrivate = NULL;
30176888252Smrg}
30276888252Smrg
30376888252Smrg/*
30476888252Smrg * LgCountRAM --
30576888252Smrg *
30676888252Smrg * Counts amount of installed RAM
30776888252Smrg */
308d2b10af6Smrg/*
309d2b10af6Smrg * XXX We need to get rid of this PIO (MArk)
310d2b10af6Smrg */
31176888252Smrgstatic int
31276888252SmrgLgCountRam(ScrnInfoPtr pScrn)
31376888252Smrg{
314d2b10af6Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
315d2b10af6Smrg    CARD8 SR14;
31676888252Smrg
317d2b10af6Smrg    vgaHWProtect(pScrn, TRUE);
31876888252Smrg
319d2b10af6Smrg    /*
320d2b10af6Smrg     * The ROM BIOS scratch pad registers contain, among other things,
321d2b10af6Smrg     * the amount of installed RDRAM for the Laguna chip.
322d2b10af6Smrg     */
323d2b10af6Smrg    SR14 = hwp->readSeq(hwp, 0x14);
32476888252Smrg
325d2b10af6Smrg    ErrorF("Scratch Pads: 0:%02x 1:%02x 2:%02x 3:%02x\n",
326d2b10af6Smrg            hwp->readSeq(hwp, 9),
327d2b10af6Smrg            hwp->readSeq(hwp, 10),
328d2b10af6Smrg            SR14,
329d2b10af6Smrg            hwp->readSeq(hwp, 0x15));
33076888252Smrg
331d2b10af6Smrg    vgaHWProtect(pScrn, FALSE);
33276888252Smrg
333d2b10af6Smrg    return 1024 * ((SR14 & 0x7) + 1);
33476888252Smrg
335d2b10af6Smrg    /*
336d2b10af6Smrg     * !!! This function seems to be incorrect...
337d2b10af6Smrg     */
33876888252Smrg}
33976888252Smrg
34076888252Smrgstatic xf86MonPtr
34176888252SmrgLgDoDDC(ScrnInfoPtr pScrn)
34276888252Smrg{
343d2b10af6Smrg    CirPtr pCir = CIRPTR(pScrn);
344d2b10af6Smrg    xf86MonPtr MonInfo = NULL;
345d2b10af6Smrg
346d2b10af6Smrg    /*
347d2b10af6Smrg     * Map the CIR memory and MMIO areas.
348d2b10af6Smrg     */
349d2b10af6Smrg    if (!CirMapMem(pCir, pScrn->scrnIndex))
350d2b10af6Smrg        return FALSE;
351d2b10af6Smrg
352d2b10af6Smrg    if (!LgI2CInit(pScrn)) {
353d2b10af6Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
354d2b10af6Smrg                    "I2C initialization failed\n");
355d2b10af6Smrg        goto unmap_out;
356d2b10af6Smrg    }
35776888252Smrg
358d2b10af6Smrg    /*
359d2b10af6Smrg     * Read and output monitor info using DDC2 over I2C bus.
360d2b10af6Smrg     */
361d2b10af6Smrg    MonInfo = xf86DoEDID_DDC2(XF86_SCRN_ARG(pScrn), pCir->I2CPtr1);
362d2b10af6Smrg    if (!MonInfo) {
363d2b10af6Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
364d2b10af6Smrg                    "Failed to obtain EDID.\n");
365d2b10af6Smrg        goto unmap_out;
366d2b10af6Smrg    }
36776888252Smrg
368d2b10af6Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
369d2b10af6Smrg                "I2C Monitor info: %p\n", (void *)MonInfo);
370d2b10af6Smrg    xf86PrintEDID(MonInfo);
371d2b10af6Smrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
372d2b10af6Smrg                "end of I2C Monitor info\n\n");
37376888252Smrg
374d2b10af6Smrg    xf86SetDDCproperties(pScrn, MonInfo);
37576888252Smrg
37676888252Smrgunmap_out:
377d2b10af6Smrg    CirUnmapMem(pCir, pScrn->scrnIndex);
37876888252Smrg
379d2b10af6Smrg    return MonInfo;
38076888252Smrg}
38176888252Smrg
382d2b10af6Smrg/*
383d2b10af6Smrg * Mandatory
384d2b10af6Smrg */
38576888252SmrgBool
38676888252SmrgLgPreInit(ScrnInfoPtr pScrn, int flags)
38776888252Smrg{
388d2b10af6Smrg    CirPtr pCir;
389d2b10af6Smrg    vgaHWPtr hwp;
390d2b10af6Smrg    MessageType from;
391d2b10af6Smrg    int i;
392d2b10af6Smrg    ClockRangePtr clockRanges;
393d2b10af6Smrg    int fbPCIReg, ioPCIReg;
394d2b10af6Smrg    const char *s;
395d2b10af6Smrg
396d2b10af6Smrg    if (flags & PROBE_DETECT) {
397d2b10af6Smrg        cirProbeDDC(pScrn,
398d2b10af6Smrg                    xf86GetEntityInfo(pScrn->entityList[0])->index);
399d2b10af6Smrg        return TRUE;
400d2b10af6Smrg    }
401d2b10af6Smrg
40276888252Smrg#ifdef LG_DEBUG
403d2b10af6Smrg    ErrorF("LgPreInit\n");
40476888252Smrg#endif
40576888252Smrg
406d2b10af6Smrg    /*
407d2b10af6Smrg     * Check the number of entities, and fail if it isn't one.
408d2b10af6Smrg     */
409d2b10af6Smrg    if (pScrn->numEntities != 1)
410d2b10af6Smrg        return FALSE;
411d2b10af6Smrg
412d2b10af6Smrg    /*
413d2b10af6Smrg     * The vgahw module should be loaded here when needed.
414d2b10af6Smrg     */
415d2b10af6Smrg    if (!xf86LoadSubModule(pScrn, "vgahw"))
416d2b10af6Smrg        return FALSE;
417d2b10af6Smrg
418d2b10af6Smrg    /*
419d2b10af6Smrg     * Allocate a vgaHWRec.
420d2b10af6Smrg     */
421d2b10af6Smrg    if (!vgaHWGetHWRec(pScrn))
422d2b10af6Smrg        return FALSE;
423d2b10af6Smrg
424d2b10af6Smrg    hwp = VGAHWPTR(pScrn);
425d2b10af6Smrg    vgaHWSetStdFuncs(hwp);
426d2b10af6Smrg    vgaHWGetIOBase(hwp);
427d2b10af6Smrg
428d2b10af6Smrg    /*
429d2b10af6Smrg     * Allocate the LgRec driverPrivate.
430d2b10af6Smrg     */
431d2b10af6Smrg    if (!LgGetRec(pScrn))
432d2b10af6Smrg        return FALSE;
433d2b10af6Smrg
434d2b10af6Smrg    pCir = CIRPTR(pScrn);
435d2b10af6Smrg    pCir->pScrn = pScrn;
43676888252Smrg
437d2b10af6Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 12
438d2b10af6Smrg    pCir->PIOReg = hwp->PIOOffset + 0x3CE;
439d2b10af6Smrg#else
440d2b10af6Smrg    pCir->PIOReg = 0x3CE;
441d2b10af6Smrg#endif
44276888252Smrg
443d2b10af6Smrg    /*
444d2b10af6Smrg     * Get the entity, and make sure it is PCI.
445d2b10af6Smrg     */
446d2b10af6Smrg    pCir->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
447d2b10af6Smrg    if (pCir->pEnt->location.type != BUS_PCI)
448d2b10af6Smrg        return FALSE;
449d2b10af6Smrg    pCir->Chipset = pCir->pEnt->chipset;
450d2b10af6Smrg
451d2b10af6Smrg    /*
452d2b10af6Smrg     * Find the PCI info for this screen.
453d2b10af6Smrg     */
454d2b10af6Smrg    pCir->PciInfo = xf86GetPciInfoForEntity(pCir->pEnt->index);
455d2b10af6Smrg#ifndef XSERVER_LIBPCIACCESS
456d2b10af6Smrg    pCir->PciTag = pciTag(PCI_DEV_BUS(pCir->PciInfo),
457d2b10af6Smrg            PCI_DEV_DEV(pCir->PciInfo), PCI_DEV_FUNC(pCir->PciInfo));
458d2b10af6Smrg#endif
45976888252Smrg
460d2b10af6Smrg    if (xf86LoadSubModule(pScrn, "int10")) {
461d2b10af6Smrg        xf86Int10InfoPtr int10InfoPtr;
46276888252Smrg
463d2b10af6Smrg        int10InfoPtr = xf86InitInt10(pCir->pEnt->index);
46476888252Smrg
465d2b10af6Smrg        if (int10InfoPtr)
466d2b10af6Smrg            xf86FreeInt10(int10InfoPtr);
467d2b10af6Smrg    }
4685c69f917Smrg
469d2b10af6Smrg    /*
470d2b10af6Smrg     * Set pScrn->monitor.
471d2b10af6Smrg     */
472d2b10af6Smrg    pScrn->monitor = pScrn->confScreen->monitor;
473d2b10af6Smrg
474d2b10af6Smrg    /*
475d2b10af6Smrg     * The first thing we should figure out is the depth, bpp, etc.
476d2b10af6Smrg     * We support both 24 bpp and 32 bpp layouts, so indicate that.
477d2b10af6Smrg     */
478d2b10af6Smrg    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support24bppFb |
479d2b10af6Smrg                                            Support32bppFb |
480d2b10af6Smrg                                            SupportConvert32to24 |
481d2b10af6Smrg                                            PreferConvert32to24)) {
482d2b10af6Smrg        return FALSE;
483d2b10af6Smrg    }
484d2b10af6Smrg    /*
485d2b10af6Smrg     * Check that the returned depth is one we support.
486d2b10af6Smrg     */
487d2b10af6Smrg    switch (pScrn->depth) {
488d2b10af6Smrg    case 8:
489d2b10af6Smrg    case 15:
490d2b10af6Smrg    case 16:
491d2b10af6Smrg    case 24:
492d2b10af6Smrg    case 32:
493d2b10af6Smrg        /*
494d2b10af6Smrg         * OK
495d2b10af6Smrg         */
496d2b10af6Smrg        break;
497d2b10af6Smrg    default:
498d2b10af6Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
499d2b10af6Smrg                    "Given depth (%d) is not supported by this "
500d2b10af6Smrg                    "driver\n", pScrn->depth);
501d2b10af6Smrg        return FALSE;
502d2b10af6Smrg    }
503d2b10af6Smrg    xf86PrintDepthBpp(pScrn);
504d2b10af6Smrg
505d2b10af6Smrg    /*
506d2b10af6Smrg     * Get the depth24 pixmap format.
507d2b10af6Smrg     */
508d2b10af6Smrg    if (pScrn->depth == 24 && pix24bpp == 0)
509d2b10af6Smrg        pix24bpp = xf86GetBppFromDepth(pScrn, 24);
510d2b10af6Smrg
511d2b10af6Smrg    /*
512d2b10af6Smrg     * This must happen after pScrn->display has been set because
513d2b10af6Smrg     * xf86SetWeight references it.
514d2b10af6Smrg     */
515d2b10af6Smrg    if (pScrn->depth > 8) {
516d2b10af6Smrg        /*
517d2b10af6Smrg         * The defaults are OK for us.
518d2b10af6Smrg         */
519d2b10af6Smrg        rgb zeros = { 0, 0, 0 };
520d2b10af6Smrg
521d2b10af6Smrg        /*
522d2b10af6Smrg         * !!! I think we can force 5-6-5 weight for 16bpp here for
523d2b10af6Smrg         * the 5462.
524d2b10af6Smrg         */
525d2b10af6Smrg
526d2b10af6Smrg        if (!xf86SetWeight(pScrn, zeros, zeros)) {
527d2b10af6Smrg            return FALSE;
528d2b10af6Smrg        } else {
529d2b10af6Smrg            /*
530d2b10af6Smrg             * XXX Check that weight returned is supported.
531d2b10af6Smrg             */
532d2b10af6Smrg            ;
533d2b10af6Smrg        }
534d2b10af6Smrg    }
53576888252Smrg
536d2b10af6Smrg    if (!xf86SetDefaultVisual(pScrn, -1))
537d2b10af6Smrg        return FALSE;
538d2b10af6Smrg
539d2b10af6Smrg    /*
540d2b10af6Smrg     * Collect all of the relevant option flags (fill in
541d2b10af6Smrg     * pScrn->options).
542d2b10af6Smrg     */
543d2b10af6Smrg    xf86CollectOptions(pScrn, NULL);
544d2b10af6Smrg
545d2b10af6Smrg    /*
546d2b10af6Smrg     * Process the options.
547d2b10af6Smrg     */
548d2b10af6Smrg    if (!(pCir->Options = malloc(sizeof(LgOptions))))
549d2b10af6Smrg        return FALSE;
550d2b10af6Smrg    memcpy(pCir->Options, LgOptions, sizeof(LgOptions));
551d2b10af6Smrg    xf86ProcessOptions(pScrn->scrnIndex,
552d2b10af6Smrg                        pScrn->options,
553d2b10af6Smrg                        pCir->Options);
554d2b10af6Smrg
555d2b10af6Smrg    pScrn->rgbBits = 6;
556d2b10af6Smrg    from = X_DEFAULT;
557d2b10af6Smrg    pCir->HWCursor = FALSE;
558d2b10af6Smrg    if (xf86GetOptValBool(pCir->Options, OPTION_HW_CURSOR,
559d2b10af6Smrg        &pCir->HWCursor))
560d2b10af6Smrg        from = X_CONFIG;
561d2b10af6Smrg
562d2b10af6Smrg    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
563d2b10af6Smrg            pCir->HWCursor ? "HW" : "SW");
564d2b10af6Smrg    if (xf86ReturnOptValBool(pCir->Options, OPTION_NOACCEL, FALSE)) {
565d2b10af6Smrg        pCir->NoAccel = TRUE;
566d2b10af6Smrg        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
567d2b10af6Smrg                    "Acceleration disabled\n");
568d2b10af6Smrg    }
569d2b10af6Smrg    if (pScrn->bitsPerPixel < 8) {
570d2b10af6Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
571d2b10af6Smrg                    "Cannot use in less than 8 bpp\n");
572d2b10af6Smrg        return FALSE;
573d2b10af6Smrg    }
574d2b10af6Smrg    /*
575d2b10af6Smrg     * Set the ChipRev, allowing config file entries to override.
576d2b10af6Smrg     */
577d2b10af6Smrg    if (pCir->pEnt->device->chipRev >= 0) {
578d2b10af6Smrg        pCir->ChipRev = pCir->pEnt->device->chipRev;
579d2b10af6Smrg        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
580d2b10af6Smrg                    "ChipRev override: %d\n", pCir->ChipRev);
581d2b10af6Smrg    } else {
582d2b10af6Smrg        pCir->ChipRev = PCI_DEV_REVISION(pCir->PciInfo);
583d2b10af6Smrg    }
58476888252Smrg
585d2b10af6Smrg    /*
586d2b10af6Smrg     * Cirrus Logic swapped the FB and IO registers in the 5465
587d2b10af6Smrg     * (by design).
588d2b10af6Smrg     */
589d2b10af6Smrg    if (PCI_CHIP_GD5465 == pCir->Chipset) {
590d2b10af6Smrg        fbPCIReg = 0;
591d2b10af6Smrg        ioPCIReg = 1;
592d2b10af6Smrg    } else {
593d2b10af6Smrg        fbPCIReg = 1;
594d2b10af6Smrg        ioPCIReg = 0;
595d2b10af6Smrg    }
59676888252Smrg
597d2b10af6Smrg    /*
598d2b10af6Smrg     * Find the frame buffer base address.
599d2b10af6Smrg     */
600d2b10af6Smrg    if (pCir->pEnt->device->MemBase != 0) {
601d2b10af6Smrg        /*
602d2b10af6Smrg         * Require that the config file value matches one of the PCI
603d2b10af6Smrg         * values.
604d2b10af6Smrg         */
605d2b10af6Smrg        if (!xf86CheckPciMemBase(pCir->PciInfo,
606d2b10af6Smrg            pCir->pEnt->device->MemBase)) {
607d2b10af6Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
608d2b10af6Smrg                        "MemBase 0x%08lX doesn't match any PCI base "
609d2b10af6Smrg                        "register.\n",
610d2b10af6Smrg                        pCir->pEnt->device->MemBase);
611d2b10af6Smrg            return FALSE;
612d2b10af6Smrg        }
613d2b10af6Smrg        pCir->FbAddress = pCir->pEnt->device->MemBase;
614d2b10af6Smrg        from = X_CONFIG;
615d2b10af6Smrg    } else {
616d2b10af6Smrg        if (PCI_REGION_BASE(pCir->PciInfo,
617d2b10af6Smrg                            fbPCIReg,
618d2b10af6Smrg                            REGION_MEM) != 0) {
619d2b10af6Smrg            pCir->FbAddress = PCI_REGION_BASE(pCir->PciInfo,
620d2b10af6Smrg                                                fbPCIReg,
621d2b10af6Smrg                                                REGION_MEM) &
622d2b10af6Smrg                                0xff000000;
623d2b10af6Smrg            from = X_PROBED;
624d2b10af6Smrg        } else {
625d2b10af6Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
626d2b10af6Smrg                        "No valid FB address in PCI config space\n");
627d2b10af6Smrg            LgFreeRec(pScrn);
628d2b10af6Smrg            return FALSE;
629d2b10af6Smrg        }
630d2b10af6Smrg    }
631d2b10af6Smrg    xf86DrvMsg(pScrn->scrnIndex, from,
632d2b10af6Smrg                "Linear framebuffer at 0x%lX\n",
633d2b10af6Smrg                (unsigned long) pCir->FbAddress);
634d2b10af6Smrg
635d2b10af6Smrg    /*
636d2b10af6Smrg     * Find the MMIO base address.
637d2b10af6Smrg     */
638d2b10af6Smrg    if (pCir->pEnt->device->IOBase != 0) {
639d2b10af6Smrg        /*
640d2b10af6Smrg         * Require that the config file value matches one of the PCI
641d2b10af6Smrg         * values.
642d2b10af6Smrg         */
643d2b10af6Smrg        if (!xf86CheckPciMemBase(pCir->PciInfo,
644d2b10af6Smrg                                    pCir->pEnt->device->IOBase)) {
645d2b10af6Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
646d2b10af6Smrg                        "IOBase 0x%08lX doesn't match any PCI base "
647d2b10af6Smrg                        "register.\n",
648d2b10af6Smrg                        pCir->pEnt->device->IOBase);
649d2b10af6Smrg            return FALSE;
650d2b10af6Smrg        }
651d2b10af6Smrg        pCir->IOAddress = pCir->pEnt->device->IOBase;
652d2b10af6Smrg        from = X_CONFIG;
653d2b10af6Smrg    } else {
654d2b10af6Smrg        if (PCI_REGION_BASE(pCir->PciInfo,
655d2b10af6Smrg                            ioPCIReg,
656d2b10af6Smrg                            REGION_MEM) != 0) {
657d2b10af6Smrg            pCir->IOAddress = PCI_REGION_BASE(pCir->PciInfo,
658d2b10af6Smrg                                                ioPCIReg,
659d2b10af6Smrg                                                REGION_MEM) &
660d2b10af6Smrg                                0xfffff000;
661d2b10af6Smrg            from = X_PROBED;
662d2b10af6Smrg        } else {
663d2b10af6Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
664d2b10af6Smrg                        "No valid MMIO address in PCI config "
665d2b10af6Smrg                        "space\n");
666d2b10af6Smrg        }
667d2b10af6Smrg    }
668d2b10af6Smrg    xf86DrvMsg(pScrn->scrnIndex, from,
669d2b10af6Smrg                "MMIO registers at 0x%lX\n",
670d2b10af6Smrg                (unsigned long) pCir->IOAddress);
671d2b10af6Smrg
672d2b10af6Smrg    /*
673d2b10af6Smrg     * If the user has specified the amount of memory in the
674d2b10af6Smrg     * XF86Config file, we respect that setting.
675d2b10af6Smrg     */
676d2b10af6Smrg    if (pCir->pEnt->device->videoRam != 0) {
677d2b10af6Smrg        pScrn->videoRam = pCir->pEnt->device->videoRam;
678d2b10af6Smrg        from = X_CONFIG;
679d2b10af6Smrg    } else {
680d2b10af6Smrg        pScrn->videoRam = LgCountRam(pScrn);
681d2b10af6Smrg        from = X_PROBED;
682d2b10af6Smrg    }
683d2b10af6Smrg    if (2048 == pScrn->videoRam) {
684d2b10af6Smrg        /*
685d2b10af6Smrg         * Two-way interleaving
686d2b10af6Smrg         */
687d2b10af6Smrg        pCir->chip.lg->memInterleave = 0x40;
688d2b10af6Smrg    } else if (4096 == pScrn->videoRam || 8192 == pScrn->videoRam) {
689d2b10af6Smrg        /*
690d2b10af6Smrg         * Four-way interleaving
691d2b10af6Smrg         */
692d2b10af6Smrg        pCir->chip.lg->memInterleave = 0x80;
693d2b10af6Smrg    } else {
694d2b10af6Smrg        /*
695d2b10af6Smrg         * One-way interleaving
696d2b10af6Smrg         */
697d2b10af6Smrg        pCir->chip.lg->memInterleave = 0x00;
69876888252Smrg    }
699d2b10af6Smrg
700d2b10af6Smrg    xf86DrvMsg(pScrn->scrnIndex, from,
701d2b10af6Smrg                "VideoRAM: %d kByte\n", pScrn->videoRam);
702d2b10af6Smrg
703d2b10af6Smrg    pCir->FbMapSize = pScrn->videoRam * 1024;
704d2b10af6Smrg    /*
705d2b10af6Smrg     * 16K for moment, will increase.
706d2b10af6Smrg     */
707d2b10af6Smrg    pCir->IoMapSize = 0x4000;
70876888252Smrg
7091e66b2a2Smrg#ifndef XSERVER_LIBPCIACCESS
710d2b10af6Smrg    pScrn->racIoFlags = RAC_COLORMAP
71176888252Smrg#ifndef EXPERIMENTAL
712d2b10af6Smrg            | RAC_VIEWPORT
71376888252Smrg#endif
714d2b10af6Smrg            ;
715d2b10af6Smrg    xf86SetOperatingState(resVgaMem, pCir->pEnt->index, ResUnusedOpr);
716d2b10af6Smrg
717d2b10af6Smrg    /*
718d2b10af6Smrg     * Register the PCI-assigned resources.
719d2b10af6Smrg     */
720d2b10af6Smrg    if (xf86RegisterResources(pCir->pEnt->index, NULL, ResExclusive)) {
721d2b10af6Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
722d2b10af6Smrg                    "xf86RegisterResources() found resource "
723d2b10af6Smrg                    "conflicts\n");
724d2b10af6Smrg        return FALSE;
725d2b10af6Smrg    }
7261e66b2a2Smrg#endif
727d2b10af6Smrg    if (!xf86LoadSubModule(pScrn, "ddc")) {
728d2b10af6Smrg        LgFreeRec(pScrn);
729d2b10af6Smrg        return FALSE;
730d2b10af6Smrg    }
73176888252Smrg
73276888252Smrg#if LGuseI2C
733d2b10af6Smrg    if (!xf86LoadSubModule(pScrn, "i2c")) {
734d2b10af6Smrg        LgFreeRec(pScrn);
735d2b10af6Smrg        return FALSE;
736d2b10af6Smrg    }
73776888252Smrg#endif
73876888252Smrg
739d2b10af6Smrg    /*
740d2b10af6Smrg     * Read and print the monitor DDC information.
741d2b10af6Smrg     */
742d2b10af6Smrg    pScrn->monitor->DDC = LgDoDDC(pScrn);
743d2b10af6Smrg
744d2b10af6Smrg    /*
745d2b10af6Smrg     * The gamma fields must be initialised when using the new cmap
746d2b10af6Smrg     * code.
747d2b10af6Smrg     */
748d2b10af6Smrg    if (pScrn->depth > 1) {
749d2b10af6Smrg        Gamma zeros = { 0.0, 0.0, 0.0 };
750d2b10af6Smrg
751d2b10af6Smrg        if (!xf86SetGamma(pScrn, zeros))
752d2b10af6Smrg            return FALSE;
753d2b10af6Smrg    }
754d2b10af6Smrg    if (xf86GetOptValBool(pCir->Options,
755d2b10af6Smrg                            OPTION_SHADOW_FB,
756d2b10af6Smrg                            &pCir->shadowFB))
757d2b10af6Smrg        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
758d2b10af6Smrg                    "ShadowFB %s.\n",
759d2b10af6Smrg                    pCir->shadowFB ? "enabled" : "disabled");
760d2b10af6Smrg
761d2b10af6Smrg    if ((s = xf86GetOptValString(pCir->Options, OPTION_ROTATE))) {
762d2b10af6Smrg        if (!xf86NameCmp(s, "CW")) {
763d2b10af6Smrg            /*
764d2b10af6Smrg             * Acceleration is disabled below for shadowfb.
765d2b10af6Smrg             */
766d2b10af6Smrg            pCir->shadowFB = TRUE;
767d2b10af6Smrg            pCir->rotate = 1;
768d2b10af6Smrg            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
769d2b10af6Smrg                        "Rotating screen clockwise - "
770d2b10af6Smrg                        "acceleration disabled\n");
771d2b10af6Smrg        } else if (!xf86NameCmp(s, "CCW")) {
772d2b10af6Smrg            pCir->shadowFB = TRUE;
773d2b10af6Smrg            pCir->rotate = -1;
774d2b10af6Smrg            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
775d2b10af6Smrg                        "Rotating screen counter clockwise - "
776d2b10af6Smrg                        "acceleration disabled\n");
777d2b10af6Smrg        } else {
778d2b10af6Smrg            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
779d2b10af6Smrg                        "\"%s\" is not a valid value for Option "
780d2b10af6Smrg                        "\"Rotate\"\n", s);
781d2b10af6Smrg            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
782d2b10af6Smrg                        "Valid options are \"CW\" or \"CCW\"\n");
783d2b10af6Smrg        }
784d2b10af6Smrg    }
785d2b10af6Smrg
786d2b10af6Smrg    if (pCir->shadowFB && !pCir->NoAccel) {
787d2b10af6Smrg        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
788d2b10af6Smrg                    "HW acceleration not supported with "
789d2b10af6Smrg                    "\"shadowFB\".\n");
790d2b10af6Smrg        pCir->NoAccel = TRUE;
791d2b10af6Smrg    }
792d2b10af6Smrg
793d2b10af6Smrg    if (pCir->rotate && pCir->HWCursor) {
794d2b10af6Smrg        xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
795d2b10af6Smrg                    "HW cursor not supported with \"rotate\".\n");
796d2b10af6Smrg        pCir->HWCursor = FALSE;
797d2b10af6Smrg    }
798d2b10af6Smrg
799d2b10af6Smrg    /*
800d2b10af6Smrg     * We use a programmable clock.
801d2b10af6Smrg     */
802d2b10af6Smrg    pScrn->progClock = TRUE;
803d2b10af6Smrg
804d2b10af6Smrg    /*
805d2b10af6Smrg     * XXX Set HW cursor use.
806d2b10af6Smrg     */
807d2b10af6Smrg
808d2b10af6Smrg    /*
809d2b10af6Smrg     * Set the min pixel clock.
810d2b10af6Smrg     */
811d2b10af6Smrg    /*
812d2b10af6Smrg     * XXX Guess, need to check this.
813d2b10af6Smrg     */
814d2b10af6Smrg    pCir->MinClock = 12000;
815d2b10af6Smrg    xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
816d2b10af6Smrg                "Min pixel clock is %d MHz\n",
817d2b10af6Smrg                pCir->MinClock / 1000);
818d2b10af6Smrg    /*
819d2b10af6Smrg     * If the user has specified RAMDAC speed in the XF86Config
820d2b10af6Smrg     * file, we respect that setting.
821d2b10af6Smrg     */
822d2b10af6Smrg    if (pCir->pEnt->device->dacSpeeds[0]) {
823d2b10af6Smrg        ErrorF("Do not specify a Clocks line for Cirrus chips\n");
824d2b10af6Smrg        return FALSE;
825d2b10af6Smrg    } else {
826d2b10af6Smrg        int speed;
827d2b10af6Smrg        int *p;
828d2b10af6Smrg        switch (pCir->Chipset) {
829d2b10af6Smrg        case PCI_CHIP_GD5462:
830d2b10af6Smrg            p = gd5462_MaxClocks;
831d2b10af6Smrg            break;
832d2b10af6Smrg        case PCI_CHIP_GD5464:
833d2b10af6Smrg        case PCI_CHIP_GD5464BD:
834d2b10af6Smrg            p = gd5464_MaxClocks;
835d2b10af6Smrg            break;
836d2b10af6Smrg        case PCI_CHIP_GD5465:
837d2b10af6Smrg            p = gd5465_MaxClocks;
838d2b10af6Smrg            break;
839d2b10af6Smrg        default:
840d2b10af6Smrg            ErrorF("???\n");
841d2b10af6Smrg            return FALSE;
842d2b10af6Smrg        }
843d2b10af6Smrg        switch (pScrn->bitsPerPixel) {
844d2b10af6Smrg        case 8:
845d2b10af6Smrg            speed = p[1];
846d2b10af6Smrg            break;
847d2b10af6Smrg        case 15:
848d2b10af6Smrg        case 16:
849d2b10af6Smrg            speed = p[2];
850d2b10af6Smrg            break;
851d2b10af6Smrg        case 24:
852d2b10af6Smrg            speed = p[3];
853d2b10af6Smrg            break;
854d2b10af6Smrg        case 32:
855d2b10af6Smrg            speed = p[4];
856d2b10af6Smrg            break;
857d2b10af6Smrg        default:
858d2b10af6Smrg            /*
859d2b10af6Smrg             * Should not get here.
860d2b10af6Smrg             */
861d2b10af6Smrg            speed = 0;
862d2b10af6Smrg            break;
863d2b10af6Smrg        }
864d2b10af6Smrg        pCir->MaxClock = speed;
865d2b10af6Smrg        from = X_PROBED;
866d2b10af6Smrg    }
867d2b10af6Smrg    xf86DrvMsg(pScrn->scrnIndex, from, "Max pixel clock is %d MHz\n",
868d2b10af6Smrg            pCir->MaxClock / 1000);
869d2b10af6Smrg
870d2b10af6Smrg    /*
871d2b10af6Smrg     * Setup the ClockRanges, which describe what clock ranges are
872d2b10af6Smrg     * available, and what sort of modes they can be used for.
873d2b10af6Smrg     */
874d2b10af6Smrg    clockRanges = xnfcalloc(sizeof(ClockRange), 1);
875d2b10af6Smrg    clockRanges->next = NULL;
876d2b10af6Smrg    clockRanges->minClock = pCir->MinClock;
877d2b10af6Smrg    clockRanges->maxClock = pCir->MaxClock;
878d2b10af6Smrg    /*
879d2b10af6Smrg     * programmable
880d2b10af6Smrg     */
881d2b10af6Smrg    clockRanges->clockIndex = -1;
882d2b10af6Smrg    /*
883d2b10af6Smrg     * XXX Check this.
884d2b10af6Smrg     */
885d2b10af6Smrg    clockRanges->interlaceAllowed = FALSE;
886d2b10af6Smrg    /*
887d2b10af6Smrg     * XXX Check this.
888d2b10af6Smrg     */
889d2b10af6Smrg    clockRanges->doubleScanAllowed = FALSE;
890d2b10af6Smrg    /*
891d2b10af6Smrg     * XXX Check this.
892d2b10af6Smrg     */
893d2b10af6Smrg    clockRanges->doubleScanAllowed = FALSE;
894d2b10af6Smrg    /*
895d2b10af6Smrg     * XXX Check this.
896d2b10af6Smrg     */
897d2b10af6Smrg    clockRanges->doubleScanAllowed = FALSE;
898d2b10af6Smrg    clockRanges->ClockMulFactor = 1;
899d2b10af6Smrg    clockRanges->ClockDivFactor = 1;
900d2b10af6Smrg    clockRanges->PrivFlags = 0;
901d2b10af6Smrg
902d2b10af6Smrg    /*
903d2b10af6Smrg     * Depending upon what sized tiles used, either 128 or 256.
904d2b10af6Smrg     */
905d2b10af6Smrg    /*
906d2b10af6Smrg     * Aw, heck.  Just say 128.
907d2b10af6Smrg     */
908d2b10af6Smrg    pCir->Rounding = 128 >> pCir->BppShift;
909d2b10af6Smrg
910d2b10af6Smrg    /*
911d2b10af6Smrg     * xf86ValidateModes will check that the mode HTotal and VTotal
912d2b10af6Smrg     * values don't exceed the chipset's limit if pScrn->maxHValue
913d2b10af6Smrg     * and pScrn->maxVValue are set.  Since our CIRValidMode()
914d2b10af6Smrg     * already takes care of this, we don't worry about setting them
915d2b10af6Smrg     * here.
916d2b10af6Smrg     */
917d2b10af6Smrg
918d2b10af6Smrg    i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
919d2b10af6Smrg                            pScrn->display->modes, clockRanges,
920d2b10af6Smrg                            LgLinePitches[pScrn->bitsPerPixel / 8 - 1],
921d2b10af6Smrg                            0, 0,
922d2b10af6Smrg                            128 * 8, 0,
923d2b10af6Smrg                            /*
924d2b10af6Smrg                             * Any virtual height is allowed.
925d2b10af6Smrg                             */
926d2b10af6Smrg                            0,
927d2b10af6Smrg                            pScrn->display->virtualX,
928d2b10af6Smrg                            pScrn->display->virtualY,
929d2b10af6Smrg                            pCir->FbMapSize, LOOKUP_BEST_REFRESH);
930d2b10af6Smrg
931d2b10af6Smrg    pCir->chip.lg->lineDataIndex =
932d2b10af6Smrg                                LgFindLineData(pScrn->displayWidth,
933d2b10af6Smrg                                                pScrn->bitsPerPixel);
934d2b10af6Smrg
935d2b10af6Smrg    if (i == -1) {
936d2b10af6Smrg        LgFreeRec(pScrn);
937d2b10af6Smrg        return FALSE;
938d2b10af6Smrg    }
939d2b10af6Smrg
940d2b10af6Smrg    /*
941d2b10af6Smrg     * Prune the modes marked as invalid.
942d2b10af6Smrg     */
943d2b10af6Smrg    xf86PruneDriverModes(pScrn);
944d2b10af6Smrg
945d2b10af6Smrg    if (i == 0 || pScrn->modes == NULL) {
946d2b10af6Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
947d2b10af6Smrg                    "No valid modes found\n");
948d2b10af6Smrg        LgFreeRec(pScrn);
949d2b10af6Smrg        return FALSE;
950d2b10af6Smrg    }
951d2b10af6Smrg
952d2b10af6Smrg    /*
953d2b10af6Smrg     * Set the CRTC parameters for all of the modes based on the type
954d2b10af6Smrg     * of mode, and the chipset's interlace requirements.  Calling
955d2b10af6Smrg     * this is required if the mode->Crtc* values are used by the
956d2b10af6Smrg     * driver and if the driver doesn't provide code to set
957d2b10af6Smrg     * them.  They are not pre-initialised at all.
958d2b10af6Smrg     */
959d2b10af6Smrg    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
960d2b10af6Smrg
961d2b10af6Smrg    /*
962d2b10af6Smrg     * Set the current mode to the first in the list.
963d2b10af6Smrg     */
964d2b10af6Smrg    pScrn->currentMode = pScrn->modes;
965d2b10af6Smrg
966d2b10af6Smrg    /*
967d2b10af6Smrg     * Print the list of modes being used.
968d2b10af6Smrg     */
969d2b10af6Smrg    xf86PrintModes(pScrn);
970d2b10af6Smrg
971d2b10af6Smrg    /*
972d2b10af6Smrg     * Set display resolution.
973d2b10af6Smrg     */
974d2b10af6Smrg    xf86SetDpi(pScrn, 0, 0);
975d2b10af6Smrg
976d2b10af6Smrg    /*
977d2b10af6Smrg     * Load bpp-specific modules.
978d2b10af6Smrg     */
979d2b10af6Smrg    switch (pScrn->bitsPerPixel) {
980d2b10af6Smrg    case 8:
981d2b10af6Smrg    case 16:
982d2b10af6Smrg    case 24:
983d2b10af6Smrg    case 32:
984d2b10af6Smrg        if (xf86LoadSubModule(pScrn, "fb") == NULL) {
985d2b10af6Smrg            LgFreeRec(pScrn);
986d2b10af6Smrg            return FALSE;
987d2b10af6Smrg        }
988d2b10af6Smrg        break;
989d2b10af6Smrg    }
990d2b10af6Smrg
991d2b10af6Smrg    /*
992d2b10af6Smrg     * Load XAA if needed.
993d2b10af6Smrg     */
994d2b10af6Smrg    if (!pCir->NoAccel) {
9955c69f917Smrg#ifdef HAVE_XAA_H
996d2b10af6Smrg        if (!xf86LoadSubModule(pScrn, "xaa"))
9975c69f917Smrg#else
998d2b10af6Smrg        if (1)
9995c69f917Smrg#endif
1000d2b10af6Smrg        {
1001d2b10af6Smrg            xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1002d2b10af6Smrg                        "Falling back to shadowfb\n");
1003d2b10af6Smrg            pCir->NoAccel = TRUE;
1004d2b10af6Smrg            pCir->shadowFB = TRUE;
1005d2b10af6Smrg        }
1006d2b10af6Smrg    }
1007d2b10af6Smrg
1008d2b10af6Smrg    /*
1009d2b10af6Smrg     * Load RAMDAC if needed.
1010d2b10af6Smrg     */
1011d2b10af6Smrg    if (pCir->HWCursor) {
1012d2b10af6Smrg        if (!xf86LoadSubModule(pScrn, "ramdac")) {
1013d2b10af6Smrg            LgFreeRec(pScrn);
1014d2b10af6Smrg            return FALSE;
1015d2b10af6Smrg        }
1016d2b10af6Smrg    }
1017d2b10af6Smrg
1018d2b10af6Smrg    if (pCir->shadowFB) {
1019d2b10af6Smrg        if (!xf86LoadSubModule(pScrn, "shadowfb")) {
1020d2b10af6Smrg            LgFreeRec(pScrn);
1021d2b10af6Smrg            return FALSE;
1022d2b10af6Smrg        }
1023d2b10af6Smrg    }
1024d2b10af6Smrg
1025d2b10af6Smrg    return TRUE;
102676888252Smrg}
102776888252Smrg
102876888252Smrg/*
102976888252Smrg * This function saves the video state.
103076888252Smrg */
103176888252Smrgstatic void
103276888252SmrgLgSave(ScrnInfoPtr pScrn)
103376888252Smrg{
1034d2b10af6Smrg    CirPtr pCir = CIRPTR(pScrn);
1035d2b10af6Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
103676888252Smrg
103776888252Smrg#ifdef LG_DEBUG
1038d2b10af6Smrg    ErrorF("LgSave\n");
103976888252Smrg#endif
104076888252Smrg
1041d2b10af6Smrg    vgaHWSave(pScrn, &VGAHWPTR(pScrn)->SavedReg, VGA_SR_ALL);
1042d2b10af6Smrg
1043d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1A] =
1044d2b10af6Smrg    pCir->chip.lg->SavedReg.ExtVga[CR1A] = hwp->readCrtc(hwp, 0x1A);
1045d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1B] =
1046d2b10af6Smrg    pCir->chip.lg->SavedReg.ExtVga[CR1B] = hwp->readCrtc(hwp, 0x1B);
1047d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1D] =
1048d2b10af6Smrg    pCir->chip.lg->SavedReg.ExtVga[CR1D] = hwp->readCrtc(hwp, 0x1D);
1049d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1E] =
1050d2b10af6Smrg    pCir->chip.lg->SavedReg.ExtVga[CR1E] = hwp->readCrtc(hwp, 0x1E);
1051d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[SR07] =
1052d2b10af6Smrg    pCir->chip.lg->SavedReg.ExtVga[SR07] = hwp->readSeq(hwp, 0x07);
1053d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[SR0E] =
1054d2b10af6Smrg    pCir->chip.lg->SavedReg.ExtVga[SR0E] = hwp->readSeq(hwp, 0x0E);
1055d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[SR1E] =
1056d2b10af6Smrg    pCir->chip.lg->SavedReg.ExtVga[SR1E] = hwp->readSeq(hwp, 0x1E);
1057d2b10af6Smrg
1058d2b10af6Smrg    pCir->chip.lg->ModeReg.FORMAT =
1059d2b10af6Smrg    pCir->chip.lg->SavedReg.FORMAT = memrw(0xC0);
1060d2b10af6Smrg
1061d2b10af6Smrg    pCir->chip.lg->ModeReg.VSC =
1062d2b10af6Smrg    pCir->chip.lg->SavedReg.VSC = memrl(0x3FC);
1063d2b10af6Smrg
1064d2b10af6Smrg    pCir->chip.lg->ModeReg.DTTC =
1065d2b10af6Smrg    pCir->chip.lg->SavedReg.DTTC = memrw(0xEA);
1066d2b10af6Smrg
1067d2b10af6Smrg    if (pCir->Chipset == PCI_CHIP_GD5465) {
1068d2b10af6Smrg        pCir->chip.lg->ModeReg.TileCtrl =
1069d2b10af6Smrg        pCir->chip.lg->SavedReg.TileCtrl = memrw(0x2C4);
1070d2b10af6Smrg    }
1071d2b10af6Smrg
1072d2b10af6Smrg    pCir->chip.lg->ModeReg.TILE =
1073d2b10af6Smrg    pCir->chip.lg->SavedReg.TILE = memrb(0x407);
1074d2b10af6Smrg
1075d2b10af6Smrg    if (pCir->Chipset == PCI_CHIP_GD5465)
1076d2b10af6Smrg        pCir->chip.lg->ModeReg.BCLK =
1077d2b10af6Smrg        pCir->chip.lg->SavedReg.BCLK = memrb(0x2C0);
1078d2b10af6Smrg    else
1079d2b10af6Smrg        pCir->chip.lg->ModeReg.BCLK =
1080d2b10af6Smrg        pCir->chip.lg->SavedReg.BCLK = memrb(0x8C);
1081d2b10af6Smrg
1082d2b10af6Smrg    pCir->chip.lg->ModeReg.CONTROL =
1083d2b10af6Smrg    pCir->chip.lg->SavedReg.CONTROL = memrw(0x402);
1084d2b10af6Smrg
1085d2b10af6Smrg    pCir->chip.lg->ModeReg.RIFCtrl =
1086d2b10af6Smrg    pCir->chip.lg->SavedReg.RIFCtrl = memrw(0x200);
1087d2b10af6Smrg
1088d2b10af6Smrg    pCir->chip.lg->ModeReg.RACCtrl =
1089d2b10af6Smrg    pCir->chip.lg->SavedReg.RACCtrl = memrw(0x202);
109076888252Smrg}
109176888252Smrg
109276888252Smrg/*
109376888252Smrg * Initialise a new mode.  This is currently still using the old
109476888252Smrg * "initialise struct, restore/write struct to HW" model.  That could
109576888252Smrg * be changed.
109676888252Smrg */
109776888252Smrgstatic Bool
109876888252SmrgLgModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
109976888252Smrg{
1100d2b10af6Smrg    vgaHWPtr hwp;
1101d2b10af6Smrg    CirPtr pCir;
1102d2b10af6Smrg    int width;
1103d2b10af6Smrg    Bool VDiv2 = FALSE;
1104d2b10af6Smrg    CARD16 clockData;
1105d2b10af6Smrg    LgLineDataPtr lineData;
110676888252Smrg
110776888252Smrg#ifdef LG_DEBUG
1108d2b10af6Smrg    ErrorF("LgModeInit %d bpp,   %d   %d %d %d %d   %d %d %d %d\n",
1109d2b10af6Smrg            pScrn->bitsPerPixel, mode->Clock,
1110d2b10af6Smrg            mode->HDisplay, mode->HSyncStart,
1111d2b10af6Smrg            mode->HSyncEnd, mode->HTotal,
1112d2b10af6Smrg            mode->VDisplay, mode->VSyncStart,
1113d2b10af6Smrg            mode->VSyncEnd, mode->VTotal);
1114d2b10af6Smrg
1115d2b10af6Smrg    ErrorF("LgModeInit: depth %d bits\n", pScrn->depth);
111676888252Smrg#endif
111776888252Smrg
1118d2b10af6Smrg    pCir = CIRPTR(pScrn);
1119d2b10af6Smrg    hwp = VGAHWPTR(pScrn);
1120d2b10af6Smrg    vgaHWUnlock(hwp);
1121d2b10af6Smrg
1122d2b10af6Smrg    if (mode->VTotal >= 1024 && !(mode->Flags & V_INTERLACE)) {
1123d2b10af6Smrg        /*
1124d2b10af6Smrg         * For non-interlaced vertical timing >= 1024, the vertical
1125d2b10af6Smrg         * timings are divided by 2 and VGA CRTC 0x17 bit 2 is set.
1126d2b10af6Smrg         */
1127d2b10af6Smrg        if (!mode->CrtcVAdjusted) {
1128d2b10af6Smrg            mode->CrtcVDisplay >>= 1;
1129d2b10af6Smrg            mode->CrtcVSyncStart >>= 1;
1130d2b10af6Smrg            mode->CrtcVSyncEnd >>= 1;
1131d2b10af6Smrg            mode->CrtcVTotal >>= 1;
1132d2b10af6Smrg            mode->CrtcVAdjusted = TRUE;
1133d2b10af6Smrg        }
1134d2b10af6Smrg        VDiv2 = TRUE;
1135d2b10af6Smrg    }
1136d2b10af6Smrg
1137d2b10af6Smrg    /*
1138d2b10af6Smrg     * Initialise the ModeReg values.
1139d2b10af6Smrg     */
1140d2b10af6Smrg    if (!vgaHWInit(pScrn, mode))
1141d2b10af6Smrg        return FALSE;
1142d2b10af6Smrg    pScrn->vtSema = TRUE;
1143d2b10af6Smrg
1144d2b10af6Smrg    if (VDiv2)
1145d2b10af6Smrg        hwp->ModeReg.CRTC[0x17] |= 0x04;
114676888252Smrg
114776888252Smrg#ifdef LG_DEBUG
1148d2b10af6Smrg    ErrorF("SynthClock = %d\n", mode->SynthClock);
114976888252Smrg#endif
1150d2b10af6Smrg    hwp->IOBase = 0x3D0;
1151d2b10af6Smrg    hwp->ModeReg.MiscOutReg |= 0x01;
1152d2b10af6Smrg/*
1153d2b10af6Smrg * Mono address
1154d2b10af6Smrg */
1155d2b10af6Smrg#if 0
1156d2b10af6Smrg    hwp->IOBase = 0x3B0;
1157d2b10af6Smrg    hwp->ModeReg.MiscOutReg &= ~0x01;
115876888252Smrg#endif
115976888252Smrg
1160d2b10af6Smrg    /*
1161d2b10af6Smrg     * ??? Should these be both ...End or ...Start, not one of each?
1162d2b10af6Smrg     */
1163d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1A] =
1164d2b10af6Smrg                        (((mode->CrtcVSyncStart + 1) & 0x300) >> 2) |
1165d2b10af6Smrg                        (((mode->CrtcHSyncEnd >> 3) & 0xC0) >> 2);
1166d2b10af6Smrg
1167d2b10af6Smrg    width = pScrn->displayWidth * pScrn->bitsPerPixel / 8;
1168d2b10af6Smrg    if (pScrn->bitsPerPixel == 1)
1169d2b10af6Smrg        width <<= 2;
1170d2b10af6Smrg    hwp->ModeReg.CRTC[0x13] = (width + 7) >> 3;
1171d2b10af6Smrg    /*
1172d2b10af6Smrg     * Offset extension (see CR13)
1173d2b10af6Smrg     */
1174d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1B] &= 0xEF;
1175d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1B] |=
1176d2b10af6Smrg            (((width + 7) >> 3) & 0x100) ? 0x10 : 0x00;
1177d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1B] |= 0x22;
1178d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1D] =
1179d2b10af6Smrg            (((width + 7) >> 3) & 0x200) ? 0x01 : 0x00;
1180d2b10af6Smrg
1181d2b10af6Smrg    /*
1182d2b10af6Smrg     * Set the 28th bit to enable extended modes.
1183d2b10af6Smrg     */
1184d2b10af6Smrg    pCir->chip.lg->ModeReg.VSC = 0x10000000;
1185d2b10af6Smrg
1186d2b10af6Smrg    /*
1187d2b10af6Smrg     * Overflow register (sure are a lot of overflow bits around...)
1188d2b10af6Smrg     */
1189d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1E] = 0x00;
1190d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1E] |= (
1191d2b10af6Smrg            (mode->CrtcHTotal >> 3 & 0x0100) ? 1 : 0) << 7;
1192d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1E] |= (
1193d2b10af6Smrg            (mode->CrtcHDisplay >> 3 & 0x0100) ? 1 : 0) << 6;
1194d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1E] |= (
1195d2b10af6Smrg            (mode->CrtcHSyncStart >> 3 & 0x0100) ? 1 : 0) << 5;
1196d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1E] |= (
1197d2b10af6Smrg            (mode->CrtcHSyncStart >> 3 & 0x0100) ? 1 : 0) << 4;
1198d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1E] |=
1199d2b10af6Smrg            ((mode->CrtcVTotal & 0x0400) ? 1 : 0) << 3;
1200d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1E] |= (
1201d2b10af6Smrg            (mode->CrtcVDisplay & 0x0400) ? 1 : 0) << 2;
1202d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1E] |= (
1203d2b10af6Smrg            (mode->CrtcVSyncStart & 0x0400) ? 1 : 0) << 1;
1204d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[CR1E] |= (
1205d2b10af6Smrg            (mode->CrtcVSyncStart & 0x0400) ? 1 : 0) << 0;
1206d2b10af6Smrg
1207d2b10af6Smrg    lineData = &LgLineData[pCir->chip.lg->lineDataIndex];
1208d2b10af6Smrg
1209d2b10af6Smrg    pCir->chip.lg->ModeReg.TILE = lineData->tilesPerLine & 0x3F;
1210d2b10af6Smrg
1211d2b10af6Smrg    if (8 == pScrn->bitsPerPixel) {
1212d2b10af6Smrg        pCir->chip.lg->ModeReg.FORMAT = 0x0000;
1213d2b10af6Smrg
1214d2b10af6Smrg        pCir->chip.lg->ModeReg.DTTC =
1215d2b10af6Smrg                (pCir->chip.lg->ModeReg.TILE << 8) |
1216d2b10af6Smrg                0x0080 |
1217d2b10af6Smrg                (lineData->width << 6);
1218d2b10af6Smrg        pCir->chip.lg->ModeReg.CONTROL = 0x0000 |
1219d2b10af6Smrg                                            (lineData->width << 11);
1220d2b10af6Smrg
1221d2b10af6Smrg        /*
1222d2b10af6Smrg         * There is an optimal FIFO threshold value (lower
1223d2b10af6Smrg         * 5 bits of DTTC) for every resolution and color depth
1224d2b10af6Smrg         * combination.  We'll hit the highlights here, and get
1225d2b10af6Smrg         * close for anything that's not covered.
1226d2b10af6Smrg         */
1227d2b10af6Smrg        if (mode->CrtcHDisplay <= 640) {
1228d2b10af6Smrg            /*
1229d2b10af6Smrg             * BAD numbers: 0x1E
1230d2b10af6Smrg             * GOOD numbers: 0x14
1231d2b10af6Smrg             */
1232d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1233d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1234d2b10af6Smrg                            (0x0014);
1235d2b10af6Smrg        } else if (mode->CrtcHDisplay <= 800) {
1236d2b10af6Smrg            /*
1237d2b10af6Smrg             * BAD numbers: 0x16
1238d2b10af6Smrg             * GOOD numbers: 0x13 0x14
1239d2b10af6Smrg             */
1240d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1241d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1242d2b10af6Smrg                            (0x0014);
1243d2b10af6Smrg        } else if (mode->CrtcHDisplay <= 1024) {
1244d2b10af6Smrg            /*
1245d2b10af6Smrg             * BAD numbers:
1246d2b10af6Smrg             * GOOD numbers: 0x15
1247d2b10af6Smrg             */
1248d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1249d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1250d2b10af6Smrg                            (0x0015);
1251d2b10af6Smrg        } else if (mode->CrtcHDisplay <= 1280) {
1252d2b10af6Smrg            /*
1253d2b10af6Smrg             * BAD numbers:
1254d2b10af6Smrg             * GOOD numbers: 0x16
1255d2b10af6Smrg             */
1256d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1257d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1258d2b10af6Smrg                            (0x0016);
1259d2b10af6Smrg        } else {
1260d2b10af6Smrg            /*
1261d2b10af6Smrg             * BAD numbers:
1262d2b10af6Smrg             * GOOD numbers:
1263d2b10af6Smrg             */
1264d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1265d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1266d2b10af6Smrg                            (0x0017);
1267d2b10af6Smrg        }
1268d2b10af6Smrg    } else if (16 == pScrn->bitsPerPixel) {
1269d2b10af6Smrg        /*
1270d2b10af6Smrg         * !!! Assume 5-6-5 RGB mode (for now...).
1271d2b10af6Smrg         */
1272d2b10af6Smrg        pCir->chip.lg->ModeReg.FORMAT = 0x1400;
1273d2b10af6Smrg
1274d2b10af6Smrg        if (pScrn->depth == 15)
1275d2b10af6Smrg            pCir->chip.lg->ModeReg.FORMAT = 0x1600;
1276d2b10af6Smrg
1277d2b10af6Smrg        pCir->chip.lg->ModeReg.DTTC =
1278d2b10af6Smrg                                (pCir->chip.lg->ModeReg.TILE << 8) |
1279d2b10af6Smrg                                0x0080 |
1280d2b10af6Smrg                                (lineData->width << 6);
1281d2b10af6Smrg        pCir->chip.lg->ModeReg.CONTROL = 0x2000 |
1282d2b10af6Smrg                                            (lineData->width << 11);
1283d2b10af6Smrg
1284d2b10af6Smrg        if (mode->CrtcHDisplay <= 640) {
1285d2b10af6Smrg            /*
1286d2b10af6Smrg             * BAD numbers: 0x12
1287d2b10af6Smrg             * GOOD numbers: 0x10
1288d2b10af6Smrg             */
1289d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1290d2b10af6Smrg                    (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1291d2b10af6Smrg                    (0x0010);
1292d2b10af6Smrg        } else if (mode->CrtcHDisplay <= 800) {
1293d2b10af6Smrg            /*
1294d2b10af6Smrg             * BAD numbers: 0x13
1295d2b10af6Smrg             * GOOD numbers: 0x11
1296d2b10af6Smrg             */
1297d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1298d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1299d2b10af6Smrg                            (0x0011);
1300d2b10af6Smrg        } else if (mode->CrtcHDisplay <= 1024) {
1301d2b10af6Smrg            /*
1302d2b10af6Smrg             * BAD numbers: 0x14
1303d2b10af6Smrg             * GOOD numbers: 0x12
1304d2b10af6Smrg             */
1305d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1306d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1307d2b10af6Smrg                            (0x0012);
1308d2b10af6Smrg        } else if (mode->CrtcHDisplay <= 1280) {
1309d2b10af6Smrg            /*
1310d2b10af6Smrg             * BAD numbers: 0x08 0x10
1311d2b10af6Smrg             * Borderline numbers: 0x12
1312d2b10af6Smrg             * GOOD numbers: 0x15
1313d2b10af6Smrg             */
1314d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1315d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1316d2b10af6Smrg                            (0x0015);
1317d2b10af6Smrg        } else {
1318d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1319d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1320d2b10af6Smrg                            (0x0017);
1321d2b10af6Smrg        }
1322d2b10af6Smrg    } else if (24 == pScrn->bitsPerPixel) {
1323d2b10af6Smrg        pCir->chip.lg->ModeReg.FORMAT = 0x2400;
1324d2b10af6Smrg
1325d2b10af6Smrg        pCir->chip.lg->ModeReg.DTTC =
1326d2b10af6Smrg                                (pCir->chip.lg->ModeReg.TILE << 8) |
1327d2b10af6Smrg                                0x0080 |
1328d2b10af6Smrg                                (lineData->width << 6);
1329d2b10af6Smrg        pCir->chip.lg->ModeReg.CONTROL = 0x4000 |
1330d2b10af6Smrg                                            (lineData->width << 11);
1331d2b10af6Smrg
1332d2b10af6Smrg        if (mode->CrtcHDisplay <= 640) {
1333d2b10af6Smrg            /*
1334d2b10af6Smrg             * BAD numbers:
1335d2b10af6Smrg             * GOOD numbers: 0x10
1336d2b10af6Smrg             */
1337d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1338d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1339d2b10af6Smrg                            (0x0010);
1340d2b10af6Smrg        } else if (mode->CrtcHDisplay <= 800) {
1341d2b10af6Smrg            /*
1342d2b10af6Smrg             * BAD numbers:
1343d2b10af6Smrg             * GOOD numbers: 0x11
1344d2b10af6Smrg             */
1345d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1346d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1347d2b10af6Smrg                            (0x0011);
1348d2b10af6Smrg        } else if (mode->CrtcHDisplay <= 1024) {
1349d2b10af6Smrg            /*
1350d2b10af6Smrg             * BAD numbers: 0x12 0x13
1351d2b10af6Smrg             * Borderline numbers: 0x15
1352d2b10af6Smrg             * GOOD numbers: 0x17
1353d2b10af6Smrg             */
1354d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1355d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1356d2b10af6Smrg                            (0x0017);
1357d2b10af6Smrg        } else if (mode->CrtcHDisplay <= 1280) {
1358d2b10af6Smrg            /*
1359d2b10af6Smrg             * BAD numbers:
1360d2b10af6Smrg             * GOOD numbers: 0x1E
1361d2b10af6Smrg             */
1362d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1363d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1364d2b10af6Smrg                            (0x001E);
1365d2b10af6Smrg        } else {
1366d2b10af6Smrg            /*
1367d2b10af6Smrg             * BAD numbers:
1368d2b10af6Smrg             * GOOD numbers:
1369d2b10af6Smrg             */
1370d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1371d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1372d2b10af6Smrg                            (0x0020);
1373d2b10af6Smrg        }
1374d2b10af6Smrg    } else if (32 == pScrn->bitsPerPixel) {
1375d2b10af6Smrg        pCir->chip.lg->ModeReg.FORMAT = 0x3400;
1376d2b10af6Smrg
1377d2b10af6Smrg        pCir->chip.lg->ModeReg.DTTC =
1378d2b10af6Smrg                                (pCir->chip.lg->ModeReg.TILE << 8) |
1379d2b10af6Smrg                                0x0080 |
1380d2b10af6Smrg                                (lineData->width << 6);
1381d2b10af6Smrg        pCir->chip.lg->ModeReg.CONTROL = 0x6000 |
1382d2b10af6Smrg                                            (lineData->width << 11);
1383d2b10af6Smrg
1384d2b10af6Smrg        if (mode->CrtcHDisplay <= 640) {
1385d2b10af6Smrg            /*
1386d2b10af6Smrg             * GOOD numbers: 0x0E
1387d2b10af6Smrg             * BAD numbers:
1388d2b10af6Smrg             */
1389d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1390d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1391d2b10af6Smrg                            (0x000E);
1392d2b10af6Smrg        } else if (mode->CrtcHDisplay <= 800) {
1393d2b10af6Smrg            /*
1394d2b10af6Smrg             * GOOD numbers: 0x17
1395d2b10af6Smrg             * BAD numbers:
1396d2b10af6Smrg             */
1397d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1398d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1399d2b10af6Smrg                            (0x0017);
1400d2b10af6Smrg        } else if (mode->CrtcHDisplay <= 1024) {
1401d2b10af6Smrg            /*
1402d2b10af6Smrg             * GOOD numbers: 0x1D
1403d2b10af6Smrg             * OKAY numbers: 0x15 0x14 0x16 0x18 0x19
1404d2b10af6Smrg             * BAD numbers: 0x0E 0x12 0x13 0x0D
1405d2b10af6Smrg             */
1406d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1407d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1408d2b10af6Smrg                            (0x001D);
1409d2b10af6Smrg        } else if (mode->CrtcHDisplay <= 1280) {
1410d2b10af6Smrg            /*
1411d2b10af6Smrg             * GOOD numbers:
1412d2b10af6Smrg             * BAD numbers:
1413d2b10af6Smrg             */
1414d2b10af6Smrg            /*
1415d2b10af6Smrg             * 10
1416d2b10af6Smrg             */
1417d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1418d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1419d2b10af6Smrg                            (0x0022);
1420d2b10af6Smrg        } else {
1421d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1422d2b10af6Smrg                            (pCir->chip.lg->ModeReg.DTTC & 0xFFE0) |
1423d2b10af6Smrg                            (0x0024);
1424d2b10af6Smrg        }
1425d2b10af6Smrg    } else {
1426d2b10af6Smrg        /*
1427d2b10af6Smrg         * ??? What could it be?  Use some sane numbers.
1428d2b10af6Smrg         */
1429d2b10af6Smrg    }
143076888252Smrg
1431d2b10af6Smrg    /*
1432d2b10af6Smrg     * Setup the appropriate memory interleaving.
1433d2b10af6Smrg     */
1434d2b10af6Smrg    pCir->chip.lg->ModeReg.DTTC |= (pCir->chip.lg->memInterleave << 8);
1435d2b10af6Smrg    pCir->chip.lg->ModeReg.TILE |= pCir->chip.lg->memInterleave & 0xC0;
1436d2b10af6Smrg
1437d2b10af6Smrg    if (PCI_CHIP_GD5465 == pCir->Chipset) {
1438d2b10af6Smrg        /*
1439d2b10af6Smrg         * The tile control information in the DTTC is also mirrored
1440d2b10af6Smrg         * elsewhere.
1441d2b10af6Smrg         */
1442d2b10af6Smrg        pCir->chip.lg->ModeReg.TileCtrl =
1443d2b10af6Smrg                                pCir->chip.lg->ModeReg.DTTC & 0xFFC0;
1444d2b10af6Smrg
1445d2b10af6Smrg        /*
1446d2b10af6Smrg         * The 5465's DTTC records _fetches_ per line, not tiles per
1447d2b10af6Smrg         * line.  Fetches are 128-byte fetches.
1448d2b10af6Smrg         */
1449d2b10af6Smrg        if (pCir->chip.lg->ModeReg.DTTC & 0x0040) {
1450d2b10af6Smrg            /*
1451d2b10af6Smrg             * Using 256-byte wide tiles.  Double the fetches per
1452d2b10af6Smrg             * line field.
1453d2b10af6Smrg             */
1454d2b10af6Smrg            pCir->chip.lg->ModeReg.DTTC =
1455d2b10af6Smrg                        (pCir->chip.lg->ModeReg.DTTC & 0xC0FF) |
1456d2b10af6Smrg                        ((pCir->chip.lg->ModeReg.DTTC & 0x3F00) << 1);
1457d2b10af6Smrg        }
1458d2b10af6Smrg    }
145976888252Smrg
1460d2b10af6Smrg    /*
1461d2b10af6Smrg     * Programme the registers.
1462d2b10af6Smrg     */
1463d2b10af6Smrg    vgaHWProtect(pScrn, TRUE);
1464d2b10af6Smrg    hwp->writeMiscOut(hwp, hwp->ModeReg.MiscOutReg);
1465d2b10af6Smrg
1466d2b10af6Smrg    clockData = LgSetClock(pCir, hwp, mode->SynthClock);
1467d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[SR0E] = (clockData >> 8) & 0xFF;
1468d2b10af6Smrg    pCir->chip.lg->ModeReg.ExtVga[SR1E] = clockData & 0xFF;
146976888252Smrg
1470d2b10af6Smrg    /*
1471d2b10af6Smrg     * Write those registers out to the card.
1472d2b10af6Smrg     */
1473d2b10af6Smrg    LgRestoreLgRegs(pScrn, &pCir->chip.lg->ModeReg);
147476888252Smrg
1475d2b10af6Smrg    /*
1476d2b10af6Smrg     * Programme the registers.
1477d2b10af6Smrg     */
1478d2b10af6Smrg    vgaHWRestore(pScrn, &hwp->ModeReg, VGA_SR_MODE | VGA_SR_CMAP);
147976888252Smrg
1480d2b10af6Smrg    vgaHWProtect(pScrn, FALSE);
1481d2b10af6Smrg
1482d2b10af6Smrg    return TRUE;
1483d2b10af6Smrg}
1484d2b10af6Smrg
1485d2b10af6Smrgstatic int
1486d2b10af6SmrgLgFindLineData(int displayWidth, int bpp)
1487d2b10af6Smrg{
1488d2b10af6Smrg    /*
1489d2b10af6Smrg     * Find the smallest tile-line-pitch such that the total byte
1490d2b10af6Smrg     * pitch is greater than or equal to displayWidth * Bpp.
1491d2b10af6Smrg     */
1492d2b10af6Smrg    int i;
1493d2b10af6Smrg
1494d2b10af6Smrg    /*
1495d2b10af6Smrg     * Some pitch sizes are duplicates in the table.  BUT, the
1496d2b10af6Smrg     * invariant is that the _first_ time a pitch occurs in the table
1497d2b10af6Smrg     * is always _before_ all other pitches greater than it.  Said in
1498d2b10af6Smrg     * another way... if all duplicate entries from the table were
1499d2b10af6Smrg     * removed, then the resulting pitch values are strictly
1500d2b10af6Smrg     * increasing.
1501d2b10af6Smrg     */
1502d2b10af6Smrg
1503d2b10af6Smrg    for (i = 0; LgLineData[i].pitch > 0; i++)
1504d2b10af6Smrg        if (LgLineData[i].pitch >= displayWidth * bpp >> 3)
1505d2b10af6Smrg            return i;
1506d2b10af6Smrg
1507d2b10af6Smrg    /*
1508d2b10af6Smrg     * Um, uh oh!
1509d2b10af6Smrg     */
1510d2b10af6Smrg    return -1;
1511d2b10af6Smrg}
151276888252Smrg
151376888252Smrgstatic void
151476888252SmrgLgRestoreLgRegs(ScrnInfoPtr pScrn, LgRegPtr lgReg)
151576888252Smrg{
1516d2b10af6Smrg    CirPtr pCir;
1517d2b10af6Smrg    vgaHWPtr hwp;
1518d2b10af6Smrg    CARD8 cr1D;
1519d2b10af6Smrg
1520d2b10af6Smrg    pCir = CIRPTR(pScrn);
1521d2b10af6Smrg
1522d2b10af6Smrg    /*
1523d2b10af6Smrg     * First, VGAish registers.
1524d2b10af6Smrg     */
1525d2b10af6Smrg    hwp = VGAHWPTR(pScrn);
1526d2b10af6Smrg    hwp->writeCrtc(hwp, 0x1A, lgReg->ExtVga[CR1A]);
1527d2b10af6Smrg    hwp->writeCrtc(hwp, 0x1B, lgReg->ExtVga[CR1B]);
1528d2b10af6Smrg    cr1D = (hwp->readCrtc(hwp, 0x1D) & ~1) |
1529d2b10af6Smrg            (lgReg->ExtVga[CR1D] & 0x01);
1530d2b10af6Smrg    hwp->writeCrtc(hwp, 0x1D, cr1D);
1531d2b10af6Smrg    hwp->writeCrtc(hwp, 0x1E, lgReg->ExtVga[CR1E]);
1532d2b10af6Smrg
1533d2b10af6Smrg    hwp->writeSeq(hwp, 0x07, lgReg->ExtVga[SR07]);
1534d2b10af6Smrg    hwp->writeSeq(hwp, 0x0E, lgReg->ExtVga[SR0E]);
1535d2b10af6Smrg    hwp->writeSeq(hwp, 0x1E, lgReg->ExtVga[SR1E]);
1536d2b10af6Smrg    memww(0xC0, lgReg->FORMAT);
1537d2b10af6Smrg
1538d2b10af6Smrg    /*
1539d2b10af6Smrg     * Vendor Specific Control is touchy.  Only bit 28 is of concern.
1540d2b10af6Smrg     */
1541d2b10af6Smrg    memwl(0x3FC, ((memrl(0x3FC) & ~(1 << 28)) |
1542d2b10af6Smrg                    (lgReg->VSC & (1 << 28))));
1543d2b10af6Smrg
1544d2b10af6Smrg    memww(0xEA, lgReg->DTTC);
1545d2b10af6Smrg
1546d2b10af6Smrg    if (pCir->Chipset == PCI_CHIP_GD5465) {
1547d2b10af6Smrg        memww(0x2C4, lgReg->TileCtrl);
1548d2b10af6Smrg    }
1549d2b10af6Smrg
1550d2b10af6Smrg    memwb(0x407, lgReg->TILE);
1551d2b10af6Smrg
1552d2b10af6Smrg    if (pCir->Chipset == PCI_CHIP_GD5465)
1553d2b10af6Smrg        memwb(0x2C0, lgReg->BCLK);
1554d2b10af6Smrg    else
1555d2b10af6Smrg        memwb(0x8C, lgReg->BCLK);
1556d2b10af6Smrg
1557d2b10af6Smrg    memww(0x402, lgReg->CONTROL);
1558d2b10af6Smrg
1559d2b10af6Smrg    memww(0x200, lgReg->RIFCtrl);
1560d2b10af6Smrg    memww(0x202, lgReg->RACCtrl);
156176888252Smrg}
156276888252Smrg
156376888252Smrg/*
156476888252Smrg * Restore the initial (text) mode.
156576888252Smrg */
156676888252Smrgstatic void
156776888252SmrgLgRestore(ScrnInfoPtr pScrn)
156876888252Smrg{
1569d2b10af6Smrg    vgaHWPtr hwp;
1570d2b10af6Smrg    vgaRegPtr vgaReg;
1571d2b10af6Smrg    CirPtr pCir;
1572d2b10af6Smrg    LgRegPtr lgReg;
157376888252Smrg
157476888252Smrg#ifdef LG_DEBUG
1575d2b10af6Smrg    ErrorF("LgRestore  pScrn = %p\n", (void *) pScrn);
157676888252Smrg#endif
157776888252Smrg
1578d2b10af6Smrg    pCir = CIRPTR(pScrn);
1579d2b10af6Smrg    hwp = VGAHWPTR(pScrn);
1580d2b10af6Smrg    vgaReg = &hwp->SavedReg;
1581d2b10af6Smrg    lgReg = &pCir->chip.lg->SavedReg;
158276888252Smrg
1583d2b10af6Smrg    vgaHWProtect(pScrn, TRUE);
158476888252Smrg
1585d2b10af6Smrg    LgRestoreLgRegs(pScrn, lgReg);
158676888252Smrg
1587d2b10af6Smrg    vgaHWRestore(pScrn, vgaReg, VGA_SR_ALL);
1588d2b10af6Smrg    vgaHWProtect(pScrn, FALSE);
158976888252Smrg}
159076888252Smrg
1591d2b10af6Smrg/*
1592d2b10af6Smrg * This gets called at the start of each server generation
1593d2b10af6Smrg */
1594d2b10af6Smrg/*
1595d2b10af6Smrg * Mandatory
1596d2b10af6Smrg */
159776888252SmrgBool
15985c69f917SmrgLgScreenInit(SCREEN_INIT_ARGS_DECL)
159976888252Smrg{
1600d2b10af6Smrg    /*
1601d2b10af6Smrg     * The vgaHW references will disappear one day
1602d2b10af6Smrg     */
1603d2b10af6Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1604d2b10af6Smrg    vgaHWPtr hwp;
1605d2b10af6Smrg    CirPtr pCir;
1606d2b10af6Smrg    int i, ret;
1607d2b10af6Smrg    VisualPtr visual;
1608d2b10af6Smrg    int displayWidth, width, height;
1609d2b10af6Smrg    unsigned char * FbBase = NULL;
161076888252Smrg
161176888252Smrg#ifdef LG_DEBUG
1612d2b10af6Smrg    ErrorF("LgScreenInit\n");
161376888252Smrg#endif
161476888252Smrg
1615d2b10af6Smrg    hwp = VGAHWPTR(pScrn);
161676888252Smrg
1617d2b10af6Smrg    /*
1618d2b10af6Smrg     * Standard 64k VGA window
1619d2b10af6Smrg     */
1620d2b10af6Smrg    hwp->MapSize = 0x10000;
162176888252Smrg
1622d2b10af6Smrg    pCir = CIRPTR(pScrn);
162376888252Smrg
1624d2b10af6Smrg    /*
1625d2b10af6Smrg     * Map the VGA memory and get the VGA IO base.
1626d2b10af6Smrg     */
1627d2b10af6Smrg    if (!vgaHWMapMem(pScrn))
1628d2b10af6Smrg        return FALSE;
162976888252Smrg
1630d2b10af6Smrg    /*
1631d2b10af6Smrg     * Map the CIR memory and MMIO areas.
1632d2b10af6Smrg     */
1633d2b10af6Smrg    if (!CirMapMem(pCir, pScrn->scrnIndex))
1634d2b10af6Smrg        return FALSE;
163576888252Smrg#ifdef EXPERIMENTAL
1636d2b10af6Smrg    lg_vgaHWSetMmioFunc(hwp, pCir->IOBase);
163776888252Smrg#endif
1638d2b10af6Smrg    vgaHWGetIOBase(hwp);
1639d2b10af6Smrg
1640d2b10af6Smrg    /*
1641d2b10af6Smrg     * Save the current state.
1642d2b10af6Smrg     */
1643d2b10af6Smrg    LgSave(pScrn);
1644d2b10af6Smrg
1645d2b10af6Smrg    /*
1646d2b10af6Smrg     * Initialise the first mode.
1647d2b10af6Smrg     */
1648d2b10af6Smrg    if (!LgModeInit(pScrn, pScrn->currentMode))
1649d2b10af6Smrg        return FALSE;
1650d2b10af6Smrg
1651d2b10af6Smrg    /*
1652d2b10af6Smrg     * Make things beautiful.
1653d2b10af6Smrg     */
1654d2b10af6Smrg    LgSaveScreen(pScreen, SCREEN_SAVER_ON);
1655d2b10af6Smrg
1656d2b10af6Smrg    /*
1657d2b10af6Smrg     * Set the viewport.
1658d2b10af6Smrg     */
1659d2b10af6Smrg    LgAdjustFrame(ADJUST_FRAME_ARGS(pScrn,
1660d2b10af6Smrg                                    pScrn->frameX0,
1661d2b10af6Smrg                                    pScrn->frameY0));
1662d2b10af6Smrg
1663d2b10af6Smrg    /*
1664d2b10af6Smrg     * The next step is to setup the screen's visuals, and initialise
1665d2b10af6Smrg     * the framebuffer code.  In cases where the framebuffer's default
1666d2b10af6Smrg     * choices for things like visual layouts and bits per RGB are OK,
1667d2b10af6Smrg     * this may be as simple as calling the framebuffer's ScreenInit()
1668d2b10af6Smrg     * function.  If not, the visuals will need to be setup before
1669d2b10af6Smrg     * calling a fb ScreenInit() function and fixed up after.
1670d2b10af6Smrg     */
1671d2b10af6Smrg
1672d2b10af6Smrg    /*
1673d2b10af6Smrg     * Reset the visual list.
1674d2b10af6Smrg     */
1675d2b10af6Smrg    miClearVisualTypes();
1676d2b10af6Smrg
1677d2b10af6Smrg    /*
1678d2b10af6Smrg     * Setup the visuals we support.
1679d2b10af6Smrg     */
1680d2b10af6Smrg    if (!miSetVisualTypes(pScrn->depth,
1681d2b10af6Smrg                            miGetDefaultVisualMask(pScrn->depth),
1682d2b10af6Smrg                            pScrn->rgbBits,
1683d2b10af6Smrg                            pScrn->defaultVisual))
1684d2b10af6Smrg        return FALSE;
1685d2b10af6Smrg
1686d2b10af6Smrg    miSetPixmapDepths();
168776888252Smrg
1688d2b10af6Smrg#ifdef LG_DEBUG
1689d2b10af6Smrg    ErrorF("LgScreenInit after miSetVisualTypes\n");
1690d2b10af6Smrg#endif
1691d2b10af6Smrg    displayWidth = pScrn->displayWidth;
1692d2b10af6Smrg    if (pCir->rotate) {
1693d2b10af6Smrg        height = pScrn->virtualX;
1694d2b10af6Smrg        width = pScrn->virtualY;
1695d2b10af6Smrg    } else {
1696d2b10af6Smrg        width = pScrn->virtualX;
1697d2b10af6Smrg        height = pScrn->virtualY;
1698d2b10af6Smrg    }
169976888252Smrg
1700d2b10af6Smrg    if (pCir->shadowFB) {
1701d2b10af6Smrg        pCir->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
1702d2b10af6Smrg        pCir->ShadowPtr = malloc(pCir->ShadowPitch * height);
1703d2b10af6Smrg        displayWidth = pCir->ShadowPitch / (pScrn->bitsPerPixel >> 3);
1704d2b10af6Smrg        FbBase = pCir->ShadowPtr;
1705d2b10af6Smrg    } else {
1706d2b10af6Smrg        pCir->ShadowPtr = NULL;
1707d2b10af6Smrg        FbBase = pCir->FbBase;
1708d2b10af6Smrg    }
170976888252Smrg
1710d2b10af6Smrg    /*
1711d2b10af6Smrg     * Call the framebuffer layer's ScreenInit function, and fill in
1712d2b10af6Smrg     * other pScreen fields.
1713d2b10af6Smrg     */
1714d2b10af6Smrg    switch (pScrn->bitsPerPixel) {
1715d2b10af6Smrg    case 8:
1716d2b10af6Smrg    case 16:
1717d2b10af6Smrg    case 24:
1718d2b10af6Smrg    case 32:
1719d2b10af6Smrg        ret = fbScreenInit(pScreen, FbBase, width, height,
1720d2b10af6Smrg                            pScrn->xDpi, pScrn->yDpi,
1721d2b10af6Smrg                            displayWidth, pScrn->bitsPerPixel);
1722d2b10af6Smrg        break;
1723d2b10af6Smrg    default:
1724d2b10af6Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1725d2b10af6Smrg                    "X11: Internal error: invalid bpp (%d) in "
1726d2b10af6Smrg                    "LgScreenInit\n",
1727d2b10af6Smrg                    pScrn->bitsPerPixel);
1728d2b10af6Smrg        ret = FALSE;
1729d2b10af6Smrg        break;
1730d2b10af6Smrg    }
1731d2b10af6Smrg    if (!ret)
1732d2b10af6Smrg        return FALSE;
173376888252Smrg
173476888252Smrg#ifdef LG_DEBUG
1735d2b10af6Smrg    ErrorF("LgScreenInit after depth dependent init\n");
173676888252Smrg#endif
173776888252Smrg
1738d2b10af6Smrg    /*
1739d2b10af6Smrg     * Override the default mask/offset settings.
1740d2b10af6Smrg     */
1741d2b10af6Smrg    if (pScrn->bitsPerPixel > 8) {
1742d2b10af6Smrg        for (i = 0; i < pScreen->numVisuals; i++) {
1743d2b10af6Smrg            visual = &pScreen->visuals[i];
1744d2b10af6Smrg            if ((visual->class | DynamicClass) == DirectColor) {
1745d2b10af6Smrg                visual->offsetRed = pScrn->offset.red;
1746d2b10af6Smrg                visual->offsetGreen = pScrn->offset.green;
1747d2b10af6Smrg                visual->offsetBlue = pScrn->offset.blue;
1748d2b10af6Smrg                visual->redMask = pScrn->mask.red;
1749d2b10af6Smrg                visual->greenMask = pScrn->mask.green;
1750d2b10af6Smrg                visual->blueMask = pScrn->mask.blue;
1751d2b10af6Smrg            }
1752d2b10af6Smrg        }
1753d2b10af6Smrg    }
1754d2b10af6Smrg
1755d2b10af6Smrg    /*
1756d2b10af6Smrg     * Must be after RGB ordering fixed.
1757d2b10af6Smrg     */
175876888252Smrg
1759d2b10af6Smrg    fbPictureInit(pScreen, 0, 0);
1760d2b10af6Smrg
1761d2b10af6Smrg    /*
1762d2b10af6Smrg     * Set initial black & white colourmap indices.
1763d2b10af6Smrg     */
1764d2b10af6Smrg    xf86SetBlackWhitePixels(pScreen);
176576888252Smrg
17665c69f917Smrg#ifdef HAVE_XAA_H
1767d2b10af6Smrg    /*
1768d2b10af6Smrg     * Initialize XAA functions.
1769d2b10af6Smrg     */
1770d2b10af6Smrg    if (!pCir->NoAccel) {
1771d2b10af6Smrg        if (!LgXAAInit(pScreen))
1772d2b10af6Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1773d2b10af6Smrg                    "Could not initialize XAA\n");
1774d2b10af6Smrg    }
17755c69f917Smrg#endif
177676888252Smrg#if 1
1777d2b10af6Smrg    pCir->DGAModeInit = LgModeInit;
1778d2b10af6Smrg    if (!CirDGAInit(pScreen))
1779d2b10af6Smrg        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1780d2b10af6Smrg                    "DGA initialization failed\n");
178176888252Smrg#endif
1782d2b10af6Smrg    xf86SetSilkenMouse(pScreen);
1783d2b10af6Smrg
1784d2b10af6Smrg    /*
1785d2b10af6Smrg     * Initialise cursor functions.
1786d2b10af6Smrg     */
1787d2b10af6Smrg    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
1788d2b10af6Smrg
1789d2b10af6Smrg    /*
1790d2b10af6Smrg     * Initialize HW cursor layer.
1791d2b10af6Smrg     */
1792d2b10af6Smrg    if (pCir->HWCursor) {
1793d2b10af6Smrg        if (!LgHWCursorInit(pScreen))
1794d2b10af6Smrg            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1795d2b10af6Smrg                    "Hardware cursor initialization failed\n");
1796d2b10af6Smrg    }
179776888252Smrg
1798d2b10af6Smrg    /*
1799d2b10af6Smrg     * Initialise default colourmap.
1800d2b10af6Smrg     */
1801d2b10af6Smrg    if (!miCreateDefColormap(pScreen))
1802d2b10af6Smrg        return FALSE;
180376888252Smrg
1804d2b10af6Smrg    if (pScrn->bitsPerPixel > 1 && pScrn->bitsPerPixel <= 8)
1805d2b10af6Smrg        vgaHWHandleColormaps(pScreen);
180676888252Smrg
1807d2b10af6Smrg    xf86DPMSInit(pScreen, LgDisplayPowerManagementSet, 0);
180876888252Smrg
1809d2b10af6Smrg    pScrn->memPhysBase = pCir->FbAddress;
1810d2b10af6Smrg    pScrn->fbOffset = 0;
181176888252Smrg
1812d2b10af6Smrg    {
1813d2b10af6Smrg        XF86VideoAdaptorPtr *ptr;
1814d2b10af6Smrg        int n;
181576888252Smrg
1816d2b10af6Smrg        n = xf86XVListGenericAdaptors(pScrn, &ptr);
1817d2b10af6Smrg        if (n)
1818d2b10af6Smrg            xf86XVScreenInit(pScreen, ptr, n);
1819d2b10af6Smrg    }
182076888252Smrg
1821d2b10af6Smrg    /*
1822d2b10af6Smrg     * Wrap the CloseScreen vector and set SaveScreen.
1823d2b10af6Smrg     */
1824d2b10af6Smrg    pScreen->SaveScreen = LgSaveScreen;
1825d2b10af6Smrg    pCir->CloseScreen = pScreen->CloseScreen;
1826d2b10af6Smrg    pScreen->CloseScreen = LgCloseScreen;
1827d2b10af6Smrg
1828d2b10af6Smrg    /*
1829d2b10af6Smrg     * Report any unused options (only for the first generation).
1830d2b10af6Smrg     */
1831d2b10af6Smrg    if (serverGeneration == 1)
1832d2b10af6Smrg        xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1833d2b10af6Smrg
1834d2b10af6Smrg    /*
1835d2b10af6Smrg     * Done
1836d2b10af6Smrg     */
1837d2b10af6Smrg    return TRUE;
183876888252Smrg}
183976888252Smrg
1840d2b10af6Smrg/*
1841d2b10af6Smrg * Usually mandatory
1842d2b10af6Smrg */
184376888252SmrgBool
18445c69f917SmrgLgSwitchMode(SWITCH_MODE_ARGS_DECL)
184576888252Smrg{
1846d2b10af6Smrg    SCRN_INFO_PTR(arg);
1847d2b10af6Smrg    return LgModeInit(pScrn, mode);
184876888252Smrg}
184976888252Smrg
1850d2b10af6Smrg#define ROUND_DOWN(x, mod) (((x) / (mod)) * (mod))
1851d2b10af6Smrg#define ROUND_UP(x, mod) ((((x) + (mod) - 1) / (mod)) * (mod))
185276888252Smrg
185376888252Smrg/*
185476888252Smrg * This function is used to initialize the Start Address - the first
185576888252Smrg * displayed location in the video memory.
185676888252Smrg */
1857d2b10af6Smrg/*
1858d2b10af6Smrg * Usually mandatory
1859d2b10af6Smrg */
1860d2b10af6Smrgvoid LgAdjustFrame(ADJUST_FRAME_ARGS_DECL) {
1861d2b10af6Smrg    SCRN_INFO_PTR(arg);
1862d2b10af6Smrg    int Base, tmp;
1863d2b10af6Smrg    CirPtr pCir = CIRPTR(pScrn);
1864d2b10af6Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
1865d2b10af6Smrg    int cursorX, cursorY;
1866d2b10af6Smrg    int middleX, middleY;
1867d2b10af6Smrg    const LgLineDataPtr lineData =
1868d2b10af6Smrg                            &LgLineData[pCir->chip.lg->lineDataIndex];
1869d2b10af6Smrg    const int viewportXRes =
1870d2b10af6Smrg            (PCI_CHIP_GD5465 == pCir->Chipset) ?
1871d2b10af6Smrg                    (24 == pScrn->bitsPerPixel ? 24 : 1) :
1872d2b10af6Smrg                    (lineData->width ? 256 : 128)
1873d2b10af6Smrg                            / (24 == pScrn->bitsPerPixel ?
1874d2b10af6Smrg                                    1 : (pScrn->bitsPerPixel >> 3));
1875d2b10af6Smrg    const int viewportYRes =
1876d2b10af6Smrg            (PCI_CHIP_GD5465 == pCir->Chipset) ?
1877d2b10af6Smrg                    1 : (24 == pScrn->bitsPerPixel ? 3 : 1);
1878d2b10af6Smrg
1879d2b10af6Smrg    /*
1880d2b10af6Smrg     * Where's the pointer?
1881d2b10af6Smrg     */
1882d2b10af6Smrg    miPointerGetPosition(inputInfo.pointer, &cursorX, &cursorY);
1883d2b10af6Smrg
1884d2b10af6Smrg    /*
1885d2b10af6Smrg     * Where's the middle of the screen?  We want to eventually know
1886d2b10af6Smrg     * which side of the screen the pointer is on.
1887d2b10af6Smrg     */
1888d2b10af6Smrg    middleX = (pScrn->frameX1 + pScrn->frameX0) / 2;
1889d2b10af6Smrg    middleY = (pScrn->frameY1 + pScrn->frameY0) / 2;
1890d2b10af6Smrg
1891d2b10af6Smrg    if (cursorX < middleX) {
1892d2b10af6Smrg        /*
1893d2b10af6Smrg         * Pointer is on left side of screen.  Round the frame value
1894d2b10af6Smrg         * down.
1895d2b10af6Smrg         */
1896d2b10af6Smrg        pScrn->frameX0 = ROUND_DOWN(pScrn->frameX0, viewportXRes);
1897d2b10af6Smrg    } else {
1898d2b10af6Smrg        /*
1899d2b10af6Smrg         * Pointer is on right side of screen.  Round the frame value
1900d2b10af6Smrg         * up.  A side effect of this rounding up is that we might
1901d2b10af6Smrg         * expose a part of the screen that's actually on the far
1902d2b10af6Smrg         * /left/ of the frame buffer.  That's because, although the
1903d2b10af6Smrg         * virtual desktop might be an integral number of tiles, the
1904d2b10af6Smrg         * display might not.  We'll just live with this artifact.
1905d2b10af6Smrg         */
1906d2b10af6Smrg        pScrn->frameX0 = ROUND_UP(pScrn->frameX0, viewportXRes);
1907d2b10af6Smrg    }
1908d2b10af6Smrg    pScrn->frameX1 = pScrn->frameX0 +
1909d2b10af6Smrg                        pScrn->currentMode->HDisplay - 1;
1910d2b10af6Smrg
1911d2b10af6Smrg    if (cursorY < middleY) {
1912d2b10af6Smrg        pScrn->frameY0 = ROUND_DOWN(pScrn->frameY0, viewportYRes);
1913d2b10af6Smrg    } else {
1914d2b10af6Smrg        pScrn->frameY0 = ROUND_UP(pScrn->frameY0, viewportYRes);
1915d2b10af6Smrg    }
1916d2b10af6Smrg    pScrn->frameY1 = pScrn->frameY0 +
1917d2b10af6Smrg                        pScrn->currentMode->VDisplay - 1;
1918d2b10af6Smrg
1919d2b10af6Smrg    if (x != pScrn->frameX0 || y != pScrn->frameY0) {
1920d2b10af6Smrg        /*
1921d2b10af6Smrg         * !!!
1922d2b10af6Smrg         */
1923d2b10af6Smrg        /*
1924d2b10af6Smrg         * We moved the frame from where xf86SetViewport() placed
1925d2b10af6Smrg         * it.  If we're using a SW cursor, that's okay -- the
1926d2b10af6Smrg         * pointer exists in the framebuffer, and those bits are
1927d2b10af6Smrg         * still all aligned.  But if we're using a HW cursor, then
1928d2b10af6Smrg         * we need to re-align the pointer.  Call SetCursorPosition()
1929d2b10af6Smrg         * with the appropriate new pointer values, adjusted to be
1930d2b10af6Smrg         * wrt the new frame.
1931d2b10af6Smrg         */
1932d2b10af6Smrg        x = pScrn->frameX0;
1933d2b10af6Smrg        y = pScrn->frameY0;
1934d2b10af6Smrg    }
1935d2b10af6Smrg
1936d2b10af6Smrg    /*
1937d2b10af6Smrg     * ??? Will this work for 1bpp?
1938d2b10af6Smrg     */
1939d2b10af6Smrg    Base = (y * lineData->pitch + (x * pScrn->bitsPerPixel / 8)) / 4;
1940d2b10af6Smrg
1941d2b10af6Smrg    if ((Base & ~0x000FFFFF) != 0) {
1942d2b10af6Smrg        /*
1943d2b10af6Smrg         * ???
1944d2b10af6Smrg         */
1945d2b10af6Smrg        ErrorF("X11: Internal error: LgAdjustFrame: cannot handle "
1946d2b10af6Smrg                "overflow\n");
1947d2b10af6Smrg        return;
1948d2b10af6Smrg    }
1949d2b10af6Smrg
1950d2b10af6Smrg    hwp->writeCrtc(hwp, 0x0C, (Base >> 8) & 0xFF);
1951d2b10af6Smrg    hwp->writeCrtc(hwp, 0x0D, Base & 0xFF);
1952d2b10af6Smrg    tmp = hwp->readCrtc(hwp, 0x1B) & 0xF2;
1953d2b10af6Smrg    tmp |= (Base >> 16) & 0x01;
1954d2b10af6Smrg    tmp |= (Base >> 15) & 0x0C;
1955d2b10af6Smrg    hwp->writeCrtc(hwp, 0x1B, tmp);
1956d2b10af6Smrg    tmp = hwp->readCrtc(hwp, 0x1D) & 0xE7;
1957d2b10af6Smrg    tmp |= (Base >> 16) & 0x18;
1958d2b10af6Smrg    hwp->writeCrtc(hwp, 0x1D, tmp);
195976888252Smrg}
196076888252Smrg
196176888252Smrg/*
196276888252Smrg * This is called when VT switching back to the X server.  Its job is
1963d2b10af6Smrg * to reinitialise the video mode.  We may wish to unmap video/MMIO
1964d2b10af6Smrg * memory too.
1965d2b10af6Smrg */
1966d2b10af6Smrg/*
1967d2b10af6Smrg * Mandatory
196876888252Smrg */
196976888252SmrgBool
19705c69f917SmrgLgEnterVT(VT_FUNC_ARGS_DECL)
197176888252Smrg{
1972d2b10af6Smrg    SCRN_INFO_PTR(arg);
1973d2b10af6Smrg    CirPtr pCir = CIRPTR(pScrn);
197476888252Smrg#ifdef LG_DEBUG
1975d2b10af6Smrg    ErrorF("LgEnterVT\n");
197676888252Smrg#endif
197776888252Smrg
1978d2b10af6Smrg    /*
1979d2b10af6Smrg     * XXX Shouldn't this be in LeaveVT?
1980d2b10af6Smrg     */
1981d2b10af6Smrg    /*
1982d2b10af6Smrg     * Disable HW cursor.
1983d2b10af6Smrg     */
1984d2b10af6Smrg    if (pCir->HWCursor)
1985d2b10af6Smrg        LgHideCursor(pScrn);
1986d2b10af6Smrg
1987d2b10af6Smrg    /*
1988d2b10af6Smrg     * Should we re-save the text mode on each VT enter?
1989d2b10af6Smrg     */
1990d2b10af6Smrg    return LgModeInit(pScrn, pScrn->currentMode);
199176888252Smrg}
199276888252Smrg
199376888252Smrg/*
1994d2b10af6Smrg * This is called when VT switching away from the X server.  Its job
1995d2b10af6Smrg * is to restore the previous (text) mode.  We may wish to remap
1996d2b10af6Smrg * video/MMIO memory too.
199776888252Smrg */
1998d2b10af6Smrg/*
1999d2b10af6Smrg * Mandatory
2000d2b10af6Smrg */
2001d2b10af6Smrgvoid LgLeaveVT(VT_FUNC_ARGS_DECL) {
2002d2b10af6Smrg    SCRN_INFO_PTR(arg);
2003d2b10af6Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
2004d2b10af6Smrg    CirPtr pCir = CIRPTR(pScrn);
200576888252Smrg#ifdef LG_DEBUG
2006d2b10af6Smrg    ErrorF("LgLeaveVT\n");
200776888252Smrg#endif
200876888252Smrg
2009d2b10af6Smrg    /*
2010d2b10af6Smrg     * XXX Shouldn't this be in EnterVT?
2011d2b10af6Smrg     */
2012d2b10af6Smrg    /*
2013d2b10af6Smrg     * Enable HW cursor.
2014d2b10af6Smrg     */
2015d2b10af6Smrg    if (pCir->HWCursor)
2016d2b10af6Smrg        LgShowCursor(pScrn);
2017d2b10af6Smrg
2018d2b10af6Smrg    LgRestore(pScrn);
2019d2b10af6Smrg    vgaHWLock(hwp);
202076888252Smrg}
202176888252Smrg
202276888252Smrg/*
2023d2b10af6Smrg * This is called at the end of each server generation.  It restores
2024d2b10af6Smrg * the original (text) mode.  It should also unmap the video memory,
2025d2b10af6Smrg * and free any per-generation data allocated by the driver.  It
2026d2b10af6Smrg * should finish by unwrapping and calling the saved CloseScreen
2027d2b10af6Smrg * function.
2028d2b10af6Smrg */
2029d2b10af6Smrg/*
2030d2b10af6Smrg * Mandatory
203176888252Smrg */
203276888252Smrgstatic Bool
20335c69f917SmrgLgCloseScreen(CLOSE_SCREEN_ARGS_DECL)
203476888252Smrg{
2035d2b10af6Smrg    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
2036d2b10af6Smrg    vgaHWPtr hwp = VGAHWPTR(pScrn);
2037d2b10af6Smrg    CirPtr pCir = CIRPTR(pScrn);
2038d2b10af6Smrg
2039d2b10af6Smrg    if (pScrn->vtSema) {
2040d2b10af6Smrg        LgRestore(pScrn);
2041d2b10af6Smrg        if (pCir->HWCursor)
2042d2b10af6Smrg            LgHideCursor(pScrn);
204376888252Smrg
2044d2b10af6Smrg        vgaHWLock(hwp);
204576888252Smrg
2046d2b10af6Smrg        CirUnmapMem(pCir, pScrn->scrnIndex);
2047d2b10af6Smrg    }
204876888252Smrg
20495c69f917Smrg#ifdef HAVE_XAA_H
2050d2b10af6Smrg    if (pCir->AccelInfoRec)
2051d2b10af6Smrg    XAADestroyInfoRec(pCir->AccelInfoRec);
2052d2b10af6Smrg    pCir->AccelInfoRec = NULL;
20535c69f917Smrg#endif
205476888252Smrg
2055d2b10af6Smrg    if (pCir->CursorInfoRec)
2056d2b10af6Smrg        xf86DestroyCursorInfoRec(pCir->CursorInfoRec);
2057d2b10af6Smrg    pCir->CursorInfoRec = NULL;
2058d2b10af6Smrg    if (pCir->DGAModes)
2059d2b10af6Smrg        free(pCir->DGAModes);
2060d2b10af6Smrg    pCir->DGAnumModes = 0;
2061d2b10af6Smrg    pCir->DGAModes = NULL;
206276888252Smrg
2063d2b10af6Smrg    pScrn->vtSema = FALSE;
206476888252Smrg
2065d2b10af6Smrg    pScreen->CloseScreen = pCir->CloseScreen;
2066d2b10af6Smrg    return (*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS);
206776888252Smrg}
206876888252Smrg
2069d2b10af6Smrg/*
2070d2b10af6Smrg * Free up any persistent data structures.
2071d2b10af6Smrg */
2072d2b10af6Smrg/*
2073d2b10af6Smrg * Optional
2074d2b10af6Smrg */
207576888252Smrgvoid
20765c69f917SmrgLgFreeScreen(FREE_SCREEN_ARGS_DECL)
207776888252Smrg{
2078d2b10af6Smrg    SCRN_INFO_PTR(arg);
207976888252Smrg#ifdef LG_DEBUG
2080d2b10af6Smrg    ErrorF("LgFreeScreen\n");
208176888252Smrg#endif
2082d2b10af6Smrg    /*
2083d2b10af6Smrg     * This only gets called when a screen is being deleted.  It does
2084d2b10af6Smrg     * not get called routinely at the end of a server generation.
2085d2b10af6Smrg     */
2086d2b10af6Smrg    if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
2087d2b10af6Smrg        vgaHWFreeHWRec(pScrn);
2088d2b10af6Smrg    LgFreeRec(pScrn);
208976888252Smrg}
209076888252Smrg
2091d2b10af6Smrg/*
2092d2b10af6Smrg * Checks if a mode is suitable for the selected chipset.
2093d2b10af6Smrg */
2094d2b10af6Smrg/*
2095d2b10af6Smrg * Optional
2096d2b10af6Smrg */
209776888252SmrgModeStatus
2098d2b10af6SmrgLgValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode,
2099d2b10af6Smrg            Bool verbose, int flags)
210076888252Smrg{
2101d2b10af6Smrg    int lace;
2102d2b10af6Smrg
2103d2b10af6Smrg    lace = 1 + ((mode->Flags & V_INTERLACE) != 0);
2104d2b10af6Smrg
2105d2b10af6Smrg    if ((mode->CrtcHDisplay <= 2048) &&
2106d2b10af6Smrg        (mode->CrtcHSyncStart <= 4096) &&
2107d2b10af6Smrg        (mode->CrtcHSyncEnd <= 4096) &&
2108d2b10af6Smrg        (mode->CrtcHTotal <= 4096) &&
2109d2b10af6Smrg        (mode->CrtcVDisplay <= 2048 * lace) &&
2110d2b10af6Smrg        (mode->CrtcVSyncStart <= 4096 * lace) &&
2111d2b10af6Smrg        (mode->CrtcVSyncEnd <= 4096 * lace) &&
2112d2b10af6Smrg        (mode->CrtcVTotal <= 4096 * lace)) {
2113d2b10af6Smrg        return (MODE_OK);
2114d2b10af6Smrg    }
2115d2b10af6Smrg    return (MODE_BAD);
211676888252Smrg}
211776888252Smrg
2118d2b10af6Smrg/*
2119d2b10af6Smrg * Do screen blanking.
2120d2b10af6Smrg */
2121d2b10af6Smrg/*
2122d2b10af6Smrg * Mandatory
2123d2b10af6Smrg */
212476888252Smrgstatic Bool
212576888252SmrgLgSaveScreen(ScreenPtr pScreen, int mode)
212676888252Smrg{
2127d2b10af6Smrg    CirPtr pCir = CIRPTR(xf86ScreenToScrn(pScreen));
2128d2b10af6Smrg    ScrnInfoPtr pScrn = NULL;
2129d2b10af6Smrg    Bool unblank;
2130d2b10af6Smrg
2131d2b10af6Smrg    unblank = xf86IsUnblank(mode);
2132d2b10af6Smrg
2133d2b10af6Smrg    if (pScreen != NULL)
2134d2b10af6Smrg        pScrn = xf86ScreenToScrn(pScreen);
2135d2b10af6Smrg
2136d2b10af6Smrg    if (pScrn != NULL && pScrn->vtSema) {
2137d2b10af6Smrg        if (unblank)
2138d2b10af6Smrg            /*
2139d2b10af6Smrg             * Power up the palette DAC.
2140d2b10af6Smrg             */
2141d2b10af6Smrg            memwb(0xB0, memrb(0xB0) & 0x7F);
2142d2b10af6Smrg        else
2143d2b10af6Smrg            /*
2144d2b10af6Smrg             * Power down the palette DAC.
2145d2b10af6Smrg             */
2146d2b10af6Smrg            memwb(0xB0, memrb(0xB0) | 0x80);
2147d2b10af6Smrg    }
2148d2b10af6Smrg
2149d2b10af6Smrg    return vgaHWSaveScreen(pScreen, mode);
215076888252Smrg}
215176888252Smrg
215276888252Smrgstatic CARD16
215376888252SmrgLgSetClock(CirPtr pCir, vgaHWPtr hwp, int freq)
215476888252Smrg{
2155d2b10af6Smrg    int ffreq, num, den;
2156d2b10af6Smrg    CARD8 tmp;
2157d2b10af6Smrg
2158d2b10af6Smrg    ErrorF("LgSetClock freq=%d.%03dMHz\n", freq / 1000, freq % 1000);
2159d2b10af6Smrg
2160d2b10af6Smrg    ffreq = freq;
2161d2b10af6Smrg    if (!CirrusFindClock(&ffreq, pCir->MaxClock, &num, &den))
2162d2b10af6Smrg        return 0;
2163d2b10af6Smrg
2164d2b10af6Smrg    ErrorF("LgSetClock: nom=%x den=%x ffreq=%d.%03dMHz\n",
2165d2b10af6Smrg            num, den, ffreq / 1000, ffreq % 1000);
2166d2b10af6Smrg
2167d2b10af6Smrg    /*
2168d2b10af6Smrg     * Set VCLK3.
2169d2b10af6Smrg     */
2170d2b10af6Smrg    /*
2171d2b10af6Smrg     * The numerator and denominator registers are switched around
2172d2b10af6Smrg     * in the Laguna chips.
2173d2b10af6Smrg     */
2174d2b10af6Smrg    tmp = hwp->readSeq(hwp, 0x0E);
2175d2b10af6Smrg    hwp->writeSeq(hwp, 0x0E, (tmp & 0x80) | den);
2176d2b10af6Smrg    hwp->writeSeq(hwp, 0x1E, num);
2177d2b10af6Smrg
2178d2b10af6Smrg    return (den << 8) | num;
217976888252Smrg}
218076888252Smrg
218176888252Smrg/*
2182d2b10af6Smrg * LgDisplayPowerManagementSet --
218376888252Smrg *
218476888252Smrg * Sets VESA Display Power Management Signaling (DPMS) Mode.
218576888252Smrg */
218676888252Smrgstatic void
2187d2b10af6SmrgLgDisplayPowerManagementSet(ScrnInfoPtr pScrn,
2188d2b10af6Smrg                            int PowerManagementMode,
2189d2b10af6Smrg                            int flags)
219076888252Smrg{
2191d2b10af6Smrg    unsigned char sr01, cr1a;
2192d2b10af6Smrg    vgaHWPtr hwp;
219376888252Smrg
219476888252Smrg#ifdef LG_DEBUG
2195d2b10af6Smrg    ErrorF("LgDisplayPowerManagementSet: %d\n", PowerManagementMode);
219676888252Smrg#endif
219776888252Smrg
2198d2b10af6Smrg    hwp = VGAHWPTR(pScrn);
2199d2b10af6Smrg
2200d2b10af6Smrg    switch (PowerManagementMode) {
2201d2b10af6Smrg    case DPMSModeOn:
2202d2b10af6Smrg        /*
2203d2b10af6Smrg         * Screen: On; HSync: On, VSync: On
2204d2b10af6Smrg         */
2205d2b10af6Smrg        sr01 = 0x00;
2206d2b10af6Smrg        cr1a = 0x00;
2207d2b10af6Smrg        break;
2208d2b10af6Smrg    case DPMSModeStandby:
2209d2b10af6Smrg        /*
2210d2b10af6Smrg         * Screen: Off; HSync: Off, VSync: On
2211d2b10af6Smrg         */
2212d2b10af6Smrg        sr01 = 0x20;
2213d2b10af6Smrg        cr1a = 0x08;
2214d2b10af6Smrg        break;
2215d2b10af6Smrg    case DPMSModeSuspend:
2216d2b10af6Smrg        /*
2217d2b10af6Smrg         * Screen: Off; HSync: On, VSync: Off
2218d2b10af6Smrg         */
2219d2b10af6Smrg        sr01 = 0x20;
2220d2b10af6Smrg        cr1a = 0x04;
2221d2b10af6Smrg        break;
2222d2b10af6Smrg    case DPMSModeOff:
2223d2b10af6Smrg        /*
2224d2b10af6Smrg         * Screen: Off; HSync: Off, VSync: Off
2225d2b10af6Smrg         */
2226d2b10af6Smrg        sr01 = 0x20;
2227d2b10af6Smrg        cr1a = 0x0c;
2228d2b10af6Smrg        break;
2229d2b10af6Smrg    default:
2230d2b10af6Smrg        return;
2231d2b10af6Smrg    }
2232d2b10af6Smrg
2233d2b10af6Smrg    sr01 |= hwp->readSeq(hwp, 0x01) & ~0x20;
2234d2b10af6Smrg    hwp->writeSeq(hwp, 0x01, sr01);
2235d2b10af6Smrg    cr1a |= hwp->readCrtc(hwp, 0x1A) & ~0x0C;
2236d2b10af6Smrg    hwp->writeCrtc(hwp, 0x1A, cr1a);
223776888252Smrg}
223876888252Smrg
223976888252Smrg#define minb(p) MMIO_IN8(hwp->MMIOBase, (p))
224076888252Smrg#define moutb(p,v) MMIO_OUT8(hwp->MMIOBase, (p),(v))
224176888252Smrg
224276888252Smrgstatic void
224376888252SmrgmmioWriteCrtc(vgaHWPtr hwp, CARD8 index, CARD8 value)
224476888252Smrg{
2245d2b10af6Smrg    moutb(index << 2, value);
224676888252Smrg}
224776888252Smrg
224876888252Smrgstatic CARD8
224976888252SmrgmmioReadCrtc(vgaHWPtr hwp, CARD8 index)
225076888252Smrg{
2251d2b10af6Smrg    return minb(index << 2);
225276888252Smrg}
225376888252Smrg
225476888252Smrgstatic void
225576888252Smrglg_vgaHWSetMmioFunc(vgaHWPtr hwp, CARD8 *base)
225676888252Smrg{
2257d2b10af6Smrg    hwp->writeCrtc = mmioWriteCrtc;
2258d2b10af6Smrg    hwp->readCrtc = mmioReadCrtc;
2259d2b10af6Smrg    hwp->MMIOBase = base;
2260d2b10af6Smrg    hwp->MMIOOffset = 0;
226176888252Smrg}
2262