smilynx_hw.c revision 7104f784
1/*
2Copyright (C) 1994-1999 The XFree86 Project, Inc.  All Rights Reserved.
3Copyright (C) 2000 Silicon Motion, Inc.  All Rights Reserved.
4Copyright (C) 2008 Francisco Jerez. All Rights Reserved.
5
6Permission is hereby granted, free of charge, to any person obtaining a copy of
7this software and associated documentation files (the "Software"), to deal in
8the Software without restriction, including without limitation the rights to
9use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10of the Software, and to permit persons to whom the Software is furnished to do
11so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
18NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23Except as contained in this notice, the names of The XFree86 Project and
24Silicon Motion shall not be used in advertising or otherwise to promote the
25sale, use or other dealings in this Software without prior written
26authorization from The XFree86 Project or Silicon Motion.
27*/
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include "smi.h"
34#include "smi_crtc.h"
35#include "smilynx.h"
36
37static unsigned int SMILynx_ddc1Read(ScrnInfoPtr pScrn);
38
39Bool
40SMILynx_HWInit(ScrnInfoPtr pScrn)
41{
42    SMIPtr pSmi = SMIPTR(pScrn);
43    SMIRegPtr mode = pSmi->mode;
44    vgaHWPtr	hwp = VGAHWPTR(pScrn);
45    int		vgaIOBase  = hwp->IOBase;
46    int		vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
47    int		vgaCRData  = vgaIOBase + VGA_CRTC_DATA_OFFSET;
48
49    ENTER();
50
51    if (pSmi->PCIBurst) {
52	mode->SR17 |= 0x20;
53    } else {
54	mode->SR17 &= ~0x20;
55    }
56
57    /* Gamma correction */
58    if (pSmi->Chipset == SMI_LYNX3DM || pSmi->Chipset == SMI_COUGAR3DR) {
59	if(pScrn->bitsPerPixel == 8)
60	    mode->SR66 = (mode->SR66 & 0x33) | 0x00; /* Both RAMLUT on, 6 bits-RAM */
61	else
62	    mode->SR66 = (mode->SR66 & 0x33) | 0x04; /* Both RAMLUT on, Gamma correct ON */
63    }
64
65    /* Program MCLK */
66    if (pSmi->MCLK > 0)
67	SMI_CommonCalcClock(pScrn->scrnIndex, pSmi->MCLK,
68			    1, 1, 63, 0, 0,
69			    pSmi->clockRange.minClock,
70			    pSmi->clockRange.maxClock,
71			    &mode->SR6A, &mode->SR6B);
72
73    if(!pSmi->useBIOS) {
74	/* Disable DAC and LCD framebuffer r/w operation */
75	mode->SR21 |= 0xB0;
76
77	/* Power down mode is standby mode, VCLK and MCLK divided by 4 in standby mode */
78	mode->SR20  = (mode->SR20 & ~0xB0) | 0x10;
79
80	/* Set DPMS state to Off */
81	mode->SR22 |= 0x30;
82
83	if (pSmi->Chipset != SMI_COUGAR3DR) {
84	    /* Select no displays */
85	    mode->SR31 &= ~0x07;
86
87	    /* Disable virtual refresh */
88	    mode->SR31 &= ~0x80;
89
90	    /* Disable expansion */
91	    mode->SR32 &= ~0x03;
92	    /* Enable autocentering */
93	    if (SMI_LYNXM_SERIES(pSmi->Chipset))
94		mode->SR32 |= 0x04;
95	    else
96		mode->SR32 &= ~0x04;
97
98	    if (pSmi->lcd == 2) /* Panel is DSTN */
99		mode->SR21 = 0x00;
100
101	    /* Enable HW LCD power sequencing */
102	    mode->SR34 |= 0x80;
103	}
104
105	/* Disable Vertical Expansion/Vertical Centering/Horizontal Centering */
106	mode->CR90[0xE] &= ~0x7;
107
108	/* use vclk1 */
109	mode->SR68 = 0x54;
110
111	if(pSmi->Dualhead){
112	    /* set LCD to vclk2 */
113	    mode->SR69 = 0x04;
114	}
115
116	/* Disable panel video */
117	mode->SRA0 = 0;
118
119	mode->CR33 = 0;
120	mode->CR3A = 0;
121    }
122
123    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x17, mode->SR17);
124    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20, mode->SR20);
125    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, mode->SR21);
126    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22, mode->SR22);
127    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, mode->SR31);
128    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32, mode->SR32);
129    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x34, mode->SR34);
130    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66, mode->SR66);
131    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x68, mode->SR68);
132    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x69, mode->SR69);
133    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A, mode->SR6A);
134    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B, mode->SR6B);
135    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0xA0, mode->SRA0);
136
137    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, mode->CR33);
138    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A, mode->CR3A);
139    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, mode->CR90[0xE]);
140
141    LEAVE(TRUE);
142}
143
144/*
145 * This function performs the inverse of the restore function: It saves all the
146 * standard and extended registers that we are going to modify to set up a video
147 * mode.
148 */
149
150void
151SMILynx_Save(ScrnInfoPtr pScrn)
152{
153    SMIPtr	pSmi = SMIPTR(pScrn);
154    int		i;
155    CARD32	offset;
156    SMIRegPtr	save = pSmi->save;
157    vgaHWPtr	hwp = VGAHWPTR(pScrn);
158    vgaRegPtr	vgaSavePtr = &hwp->SavedReg;
159    int		vgaIOBase  = hwp->IOBase;
160    int		vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
161    int		vgaCRData  = vgaIOBase + VGA_CRTC_DATA_OFFSET;
162
163    ENTER();
164
165    /* Save the standard VGA registers */
166    vgaHWSave(pScrn, vgaSavePtr, VGA_SR_ALL);
167    save->smiDACMask = VGAIN8(pSmi, VGA_DAC_MASK);
168    VGAOUT8(pSmi, VGA_DAC_READ_ADDR, 0);
169    for (i = 0; i < 256; i++) {
170	save->smiDacRegs[i][0] = VGAIN8(pSmi, VGA_DAC_DATA);
171	save->smiDacRegs[i][1] = VGAIN8(pSmi, VGA_DAC_DATA);
172	save->smiDacRegs[i][2] = VGAIN8(pSmi, VGA_DAC_DATA);
173    }
174    for (i = 0, offset = 2; i < 8192; i++, offset += 8)
175	save->smiFont[i] = *(pSmi->FBBase + offset);
176
177    /* Now we save all the extended registers we need. */
178    save->SR17 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x17);
179    save->SR18 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18);
180
181    save->SR20 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20);
182    save->SR21 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
183    save->SR22 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22);
184    save->SR23 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x23);
185    save->SR24 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x24);
186
187    save->SR31 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31);
188    save->SR32 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32);
189
190    save->SR66 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66);
191    save->SR68 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x68);
192    save->SR69 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x69);
193    save->SR6A = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A);
194    save->SR6B = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B);
195    save->SR6C = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6C);
196    save->SR6D = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6D);
197
198    save->SR81 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81);
199    save->SRA0 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0xA0);
200
201    if (pSmi->Dualhead) {
202	/* dualhead stuff */
203	save->SR40 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x40);
204	save->SR41 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x41);
205	save->SR42 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x42);
206	save->SR43 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x43);
207	save->SR44 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x44);
208	save->SR45 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x45);
209	save->SR48 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x48);
210	save->SR49 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x49);
211	save->SR4A = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4A);
212	save->SR4B = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4B);
213	save->SR4C = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4C);
214
215	save->SR50 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x50);
216	save->SR51 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x51);
217	save->SR52 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x52);
218	save->SR53 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x53);
219	save->SR54 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x54);
220	save->SR55 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x55);
221	save->SR56 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x56);
222	save->SR57 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x57);
223	save->SR5A = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x5A);
224
225	/* PLL2 stuff */
226	save->SR6E = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6E);
227	save->SR6F = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6F);
228    }
229
230    if (SMI_LYNXM_SERIES(pSmi->Chipset)) {
231	/* Save common registers */
232	save->CR30 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x30);
233	save->CR3A = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A);
234	for (i = 0; i < 15; i++) {
235	    save->CR90[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x90 + i);
236	}
237	for (i = 0; i < 14; i++) {
238	    save->CRA0[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0xA0 + i);
239	}
240
241	/* Save primary registers */
242	VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, save->CR90[14] & ~0x20);
243
244	save->CR33 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33);
245	for (i = 0; i < 14; i++) {
246	    save->CR40[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i);
247	}
248	save->CR9F = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9F);
249
250	/* Save secondary registers */
251	VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, save->CR90[14] | 0x20);
252	save->CR33_2 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33);
253	for (i = 0; i < 14; i++) {
254	    save->CR40_2[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i);
255	}
256	save->CR9F_2 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9F);
257
258	/* PDR#1069 */
259	VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E, save->CR90[14]);
260
261    }
262    else {
263	save->CR30 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x30);
264	save->CR33 = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33);
265	save->CR3A = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A);
266	for (i = 0; i < 14; i++) {
267	    save->CR40[i] = VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i);
268	}
269    }
270
271    save->DPR10 = READ_DPR(pSmi, 0x10);
272    save->DPR1C = READ_DPR(pSmi, 0x1C);
273    save->DPR20 = READ_DPR(pSmi, 0x20);
274    save->DPR24 = READ_DPR(pSmi, 0x24);
275    save->DPR28 = READ_DPR(pSmi, 0x28);
276    save->DPR2C = READ_DPR(pSmi, 0x2C);
277    save->DPR30 = READ_DPR(pSmi, 0x30);
278    save->DPR3C = READ_DPR(pSmi, 0x3C);
279    save->DPR40 = READ_DPR(pSmi, 0x40);
280    save->DPR44 = READ_DPR(pSmi, 0x44);
281
282    save->VPR00 = READ_VPR(pSmi, 0x00);
283    save->VPR0C = READ_VPR(pSmi, 0x0C);
284    save->VPR10 = READ_VPR(pSmi, 0x10);
285
286    if (pSmi->Chipset == SMI_COUGAR3DR) {
287	save->FPR00_ = READ_FPR(pSmi, FPR00);
288	save->FPR0C_ = READ_FPR(pSmi, FPR0C);
289	save->FPR10_ = READ_FPR(pSmi, FPR10);
290    }
291
292    save->CPR00 = READ_CPR(pSmi, 0x00);
293
294    if (!pSmi->ModeStructInit) {
295	vgaHWCopyReg(&hwp->ModeReg, vgaSavePtr);
296	memcpy(pSmi->mode, save, sizeof(SMIRegRec));
297	pSmi->ModeStructInit = TRUE;
298    }
299
300    if (pSmi->useBIOS && pSmi->pInt10 != NULL) {
301	pSmi->pInt10->num = 0x10;
302	pSmi->pInt10->ax = 0x0F00;
303	xf86ExecX86int10(pSmi->pInt10);
304	save->mode = pSmi->pInt10->ax & 0x007F;
305	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Current mode 0x%02X.\n",
306		   save->mode);
307    }
308
309    if (xf86GetVerbosity() > 1) {
310	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
311		       "Saved current video mode.  Register dump:\n");
312	SMI_PrintRegs(pScrn);
313    }
314
315    LEAVE();
316}
317
318/*
319 * This function is used to restore a video mode. It writes out all of the
320 * standard VGA and extended registers needed to setup a video mode.
321 */
322
323void
324SMILynx_WriteMode(ScrnInfoPtr pScrn, vgaRegPtr vgaSavePtr, SMIRegPtr restore)
325{
326    SMIPtr	pSmi = SMIPTR(pScrn);
327    int		i;
328    CARD8	tmp;
329    CARD32	offset;
330    vgaHWPtr	hwp = VGAHWPTR(pScrn);
331    int		vgaIOBase  = hwp->IOBase;
332    int		vgaCRIndex = vgaIOBase + VGA_CRTC_INDEX_OFFSET;
333    int		vgaCRData  = vgaIOBase + VGA_CRTC_DATA_OFFSET;
334
335    ENTER();
336
337    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x17, restore->SR17);
338    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x18, restore->SR18);
339
340    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x20, restore->SR20);
341    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, restore->SR21);
342    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x22, restore->SR22);
343    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x23, restore->SR23);
344    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x24, restore->SR24);
345
346    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x31, restore->SR31);
347    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x32, restore->SR32);
348
349    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x66, restore->SR66);
350    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x68, restore->SR68);
351    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x69, restore->SR69);
352    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6A, restore->SR6A);
353    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6B, restore->SR6B);
354    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6C, restore->SR6C);
355    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6D, restore->SR6D);
356
357    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x81, restore->SR81);
358    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0xA0, restore->SRA0);
359
360    if (pSmi->useBIOS && restore->mode != 0){
361	pSmi->pInt10->num = 0x10;
362	pSmi->pInt10->ax = restore->mode | 0x80;
363	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode 0x%02X\n",
364		   restore->mode);
365	xf86ExecX86int10(pSmi->pInt10);
366
367	/* Enable linear mode. */
368	outb(pSmi->PIOBase + VGA_SEQ_INDEX, 0x18);
369	tmp = inb(pSmi->PIOBase + VGA_SEQ_DATA);
370	outb(pSmi->PIOBase + VGA_SEQ_DATA, tmp | 0x01);
371
372	/* Enable DPR/VPR registers. */
373	tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21);
374	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x21, tmp & ~0x03);
375    } else {
376	/* Restore the standard VGA registers */
377	vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL);
378	if (restore->smiDACMask) {
379	    VGAOUT8(pSmi, VGA_DAC_MASK, restore->smiDACMask);
380	} else {
381	    VGAOUT8(pSmi, VGA_DAC_MASK, 0xFF);
382	}
383	VGAOUT8(pSmi, VGA_DAC_WRITE_ADDR, 0);
384	for (i = 0; i < 256; i++) {
385	    VGAOUT8(pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][0]);
386	    VGAOUT8(pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][1]);
387	    VGAOUT8(pSmi, VGA_DAC_DATA, restore->smiDacRegs[i][2]);
388	}
389	for (i = 0, offset = 2; i < 8192; i++, offset += 8) {
390	    *(pSmi->FBBase + offset) = restore->smiFont[i];
391	}
392
393	if (SMI_LYNXM_SERIES(pSmi->Chipset)) {
394	    /* Restore secondary registers */
395	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E,
396			  restore->CR90[14] | 0x20);
397
398	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33_2);
399	    for (i = 0; i < 14; i++) {
400		VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i,
401			      restore->CR40_2[i]);
402	    }
403	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9F, restore->CR9F_2);
404
405	    /* Restore primary registers */
406	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9E,
407			  restore->CR90[14] & ~0x20);
408
409	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33);
410	    for (i = 0; i < 14; i++) {
411		VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i,
412			      restore->CR40[i]);
413	    }
414	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x9F, restore->CR9F);
415
416	    /* Restore common registers */
417	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x30, restore->CR30);
418	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A, restore->CR3A);
419
420	    for (i = 0; i < 15; i++)
421		VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x90 + i,
422			      restore->CR90[i]);
423
424	    for (i = 0; i < 14; i++)
425		VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0xA0 + i,
426			      restore->CRA0[i]);
427
428	}else{
429	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x30, restore->CR30);
430	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x33, restore->CR33);
431	    VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x3A, restore->CR3A);
432	    for (i = 0; i < 14; i++) {
433		VGAOUT8_INDEX(pSmi, vgaCRIndex, vgaCRData, 0x40 + i,
434			      restore->CR40[i]);
435	    }
436	}
437
438	if (pSmi->Dualhead) {
439	    /* dualhead stuff */
440	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x40, restore->SR40);
441	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x41, restore->SR41);
442	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x42, restore->SR42);
443	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x43, restore->SR43);
444	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x44, restore->SR44);
445	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x45, restore->SR45);
446	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x48, restore->SR48);
447	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x49, restore->SR49);
448	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4A, restore->SR4A);
449	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4B, restore->SR4B);
450	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x4C, restore->SR4C);
451
452	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x50, restore->SR50);
453	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x51, restore->SR51);
454	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x52, restore->SR52);
455	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x53, restore->SR53);
456	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x54, restore->SR54);
457	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x55, restore->SR55);
458	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x56, restore->SR56);
459	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x57, restore->SR57);
460	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x5A, restore->SR5A);
461
462	    /* PLL2 stuff */
463	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6E, restore->SR6E);
464	    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x6F, restore->SR6F);
465	}
466    }
467
468    /* Reset the graphics engine */
469    WRITE_DPR(pSmi, 0x10, restore->DPR10);
470    WRITE_DPR(pSmi, 0x1C, restore->DPR1C);
471    WRITE_DPR(pSmi, 0x20, restore->DPR20);
472    WRITE_DPR(pSmi, 0x24, restore->DPR24);
473    WRITE_DPR(pSmi, 0x28, restore->DPR28);
474    WRITE_DPR(pSmi, 0x2C, restore->DPR2C);
475    WRITE_DPR(pSmi, 0x30, restore->DPR30);
476    WRITE_DPR(pSmi, 0x3C, restore->DPR3C);
477    WRITE_DPR(pSmi, 0x40, restore->DPR40);
478    WRITE_DPR(pSmi, 0x44, restore->DPR44);
479
480    /* write video controller regs */
481    WRITE_VPR(pSmi, 0x00, restore->VPR00);
482    WRITE_VPR(pSmi, 0x0C, restore->VPR0C);
483    WRITE_VPR(pSmi, 0x10, restore->VPR10);
484
485    if(pSmi->Chipset == SMI_COUGAR3DR) {
486	WRITE_FPR(pSmi, FPR00, restore->FPR00_);
487	WRITE_FPR(pSmi, FPR0C, restore->FPR0C_);
488	WRITE_FPR(pSmi, FPR10, restore->FPR10_);
489    }
490
491    WRITE_CPR(pSmi, 0x00, restore->CPR00);
492
493    if (xf86GetVerbosity() > 1) {
494	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, VERBLEV,
495		       "Done restoring mode.  Register dump:\n");
496	SMI_PrintRegs(pScrn);
497    }
498
499    vgaHWProtect(pScrn, FALSE);
500
501    LEAVE();
502}
503
504
505/*
506 * SMI_DisplayPowerManagementSet -- Sets VESA Display Power Management
507 * Signaling (DPMS) Mode.
508 */
509void
510SMILynx_DisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode,
511							  int flags)
512{
513    SMIPtr	pSmi = SMIPTR(pScrn);
514    SMIRegPtr	mode = pSmi->mode;
515    vgaHWPtr	hwp = VGAHWPTR(pScrn);
516
517    ENTER();
518
519    /* If we already are in the requested DPMS mode, just return */
520    if (pSmi->CurrentDPMS != PowerManagementMode) {
521	/* Read the required SR registers for the DPMS handler */
522	CARD8 SR01 = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01);
523
524	switch (PowerManagementMode) {
525	    case DPMSModeOn:
526		SR01 &= ~0x20; /* Screen on */
527		mode->SR23 &= ~0xC0; /* Disable chip activity detection */
528		break;
529	    case DPMSModeStandby:
530	    case DPMSModeSuspend:
531	    case DPMSModeOff:
532		SR01 |= 0x20; /* Screen off */
533		mode->SR23 = (mode->SR23 & ~0x07) | 0xD8; /* Enable chip activity detection
534							     Enable internal auto-standby mode
535							     Enable both IO Write and Host Memory write detect
536							     0 minutes timeout */
537		break;
538	}
539
540	/* Wait for vertical retrace */
541	while (hwp->readST01(hwp) & 0x8) ;
542	while (!(hwp->readST01(hwp) & 0x8)) ;
543
544	/* Write the registers */
545	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x01, SR01);
546	VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x23, mode->SR23);
547
548	/* Set the DPMS mode to every output and CRTC */
549	xf86DPMSSet(pScrn, PowerManagementMode, flags);
550
551	/* Save the current power state */
552	pSmi->CurrentDPMS = PowerManagementMode;
553    }
554
555    LEAVE();
556}
557
558static unsigned int
559SMILynx_ddc1Read(ScrnInfoPtr pScrn)
560{
561    register vgaHWPtr hwp = VGAHWPTR(pScrn);
562    SMIPtr pSmi = SMIPTR(pScrn);
563    unsigned int ret;
564
565    ENTER();
566
567    while (hwp->readST01(hwp) & 0x8) ;
568    while (!(hwp->readST01(hwp) & 0x8)) ;
569
570    ret = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72) & 0x08;
571
572    LEAVE(ret);
573}
574
575xf86MonPtr
576SMILynx_ddc1(ScrnInfoPtr pScrn)
577{
578    SMIPtr pSmi = SMIPTR(pScrn);
579    xf86MonPtr pMon;
580    unsigned char tmp;
581
582    ENTER();
583
584    tmp = VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72);
585    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72, tmp | 0x20);
586
587    pMon = xf86PrintEDID(xf86DoEDID_DDC1(pScrn->scrnIndex,
588					 vgaHWddc1SetSpeedWeak(),
589					 SMILynx_ddc1Read));
590    VGAOUT8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, 0x72, tmp);
591
592    LEAVE(pMon);
593}
594
595
596/* This function is used to debug, it prints out the contents of Lynx regs */
597void
598SMILynx_PrintRegs(ScrnInfoPtr pScrn)
599{
600    unsigned char i;
601    SMIPtr pSmi = SMIPTR(pScrn);
602    vgaHWPtr hwp = VGAHWPTR(pScrn);
603    int vgaCRIndex = hwp->IOBase + VGA_CRTC_INDEX_OFFSET;
604    int vgaCRReg   = hwp->IOBase + VGA_CRTC_DATA_OFFSET;
605    int vgaStatus  = hwp->IOBase + VGA_IN_STAT_1_OFFSET;
606
607    xf86ErrorFVerb(VERBLEV, "MISCELLANEOUS OUTPUT\n    %02X\n",
608		   VGAIN8(pSmi, VGA_MISC_OUT_R));
609
610    xf86ErrorFVerb(VERBLEV, "\nSEQUENCER\n"
611		   "    x0 x1 x2 x3  x4 x5 x6 x7  x8 x9 xA xB  xC xD xE xF");
612    for (i = 0x00; i <= 0xAF; i++) {
613	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
614	if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " ");
615	xf86ErrorFVerb(VERBLEV, "%02X ",
616		       VGAIN8_INDEX(pSmi, VGA_SEQ_INDEX, VGA_SEQ_DATA, i));
617    }
618
619    xf86ErrorFVerb(VERBLEV, "\n\nCRT CONTROLLER\n"
620		   "    x0 x1 x2 x3  x4 x5 x6 x7  x8 x9 xA xB  xC xD xE xF");
621    for (i = 0x00; i <= 0xAD; i++) {
622	if (i == 0x20) i = 0x30;
623	if (i == 0x50) i = 0x90;
624	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
625	if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " ");
626	xf86ErrorFVerb(VERBLEV, "%02X ",
627		       VGAIN8_INDEX(pSmi, vgaCRIndex, vgaCRReg, i));
628    }
629
630    xf86ErrorFVerb(VERBLEV, "\n\nGRAPHICS CONTROLLER\n"
631		   "    x0 x1 x2 x3  x4 x5 x6 x7  x8 x9 xA xB  xC xD xE xF");
632    for (i = 0x00; i <= 0x08; i++) {
633	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
634	if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " ");
635	xf86ErrorFVerb(VERBLEV, "%02X ",
636		       VGAIN8_INDEX(pSmi, VGA_GRAPH_INDEX, VGA_GRAPH_DATA, i));
637    }
638
639    xf86ErrorFVerb(VERBLEV, "\n\nATTRIBUTE 0CONTROLLER\n"
640		   "    x0 x1 x2 x3  x4 x5 x6 x7  x8 x9 xA xB  xC xD xE xF");
641    for (i = 0x00; i <= 0x14; i++) {
642	(void) VGAIN8(pSmi, vgaStatus);
643	if ((i & 0xF) == 0x0) xf86ErrorFVerb(VERBLEV, "\n%02X|", i);
644	if ((i & 0x3) == 0x0) xf86ErrorFVerb(VERBLEV, " ");
645	xf86ErrorFVerb(VERBLEV, "%02X ",
646		       VGAIN8_INDEX(pSmi, VGA_ATTR_INDEX, VGA_ATTR_DATA_R, i));
647    }
648    (void) VGAIN8(pSmi, vgaStatus);
649    VGAOUT8(pSmi, VGA_ATTR_INDEX, 0x20);
650}
651