s3_IBMRGB.c revision b27e1915
1340e3fbdSmrg/*
2340e3fbdSmrg *      Copyright 2001  Ani Joshi <ajoshi@unixbox.com>
3340e3fbdSmrg *
4340e3fbdSmrg *      XFree86 4.x driver for S3 chipsets
5340e3fbdSmrg *
6340e3fbdSmrg *
7340e3fbdSmrg * Permission to use, copy, modify, distribute, and sell this software and its
8340e3fbdSmrg * documentation for any purpose is hereby granted without fee, provided that
9340e3fbdSmrg * the above copyright notice appear in all copies and that both that copyright
10340e3fbdSmrg * notice and this permission notice appear in supporting documentation and
11340e3fbdSmrg * that the name of Ani Joshi not be used in advertising or
12340e3fbdSmrg * publicity pertaining to distribution of the software without specific,
13340e3fbdSmrg * written prior permission.  Ani Joshi makes no representations
14340e3fbdSmrg * about the suitability of this software for any purpose.  It is provided
15340e3fbdSmrg * "as-is" without express or implied warranty.
16340e3fbdSmrg *
17340e3fbdSmrg * ANI JOSHI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18340e3fbdSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19340e3fbdSmrg * EVENT SHALL ANI JOSHI BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20340e3fbdSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21340e3fbdSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22340e3fbdSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23340e3fbdSmrg * PERFORMANCE OF THIS SOFTWARE.
24340e3fbdSmrg *
25340e3fbdSmrg *
26340e3fbdSmrg */
27340e3fbdSmrg
28340e3fbdSmrg#ifdef HAVE_CONFIG_H
29340e3fbdSmrg#include "config.h"
30340e3fbdSmrg#endif
31340e3fbdSmrg
32340e3fbdSmrg#include "xf86.h"
33340e3fbdSmrg#include "xf86_OSproc.h"
34340e3fbdSmrg
35340e3fbdSmrg#include "compiler.h"
36340e3fbdSmrg
37340e3fbdSmrg#include "IBM.h"
38340e3fbdSmrg
39340e3fbdSmrg#include "s3.h"
40340e3fbdSmrg
41340e3fbdSmrg
42340e3fbdSmrg#define IBMRGB_WRITE_ADDR           0x3C8   /* CR55 low bit == 0 */
43340e3fbdSmrg#define IBMRGB_RAMDAC_DATA          0x3C9   /* CR55 low bit == 0 */
44340e3fbdSmrg#define IBMRGB_PIXEL_MASK           0x3C6   /* CR55 low bit == 0 */
45340e3fbdSmrg#define IBMRGB_READ_ADDR            0x3C7   /* CR55 low bit == 0 */
46340e3fbdSmrg#define IBMRGB_INDEX_LOW            0x3C8   /* CR55 low bit == 1 */
47340e3fbdSmrg#define IBMRGB_INDEX_HIGH           0x3C9   /* CR55 low bit == 1 */
48340e3fbdSmrg#define IBMRGB_INDEX_DATA           0x3C6   /* CR55 low bit == 1 */
49340e3fbdSmrg#define IBMRGB_INDEX_CONTROL        0x3C7   /* CR55 low bit == 1 */
50340e3fbdSmrg
51340e3fbdSmrg
52340e3fbdSmrgstatic void S3OutIBMRGBIndReg(ScrnInfoPtr pScrn, CARD32 reg,
53340e3fbdSmrg		       unsigned char mask, unsigned char data)
54340e3fbdSmrg{
55340e3fbdSmrg	S3Ptr pS3 = S3PTR(pScrn);
56340e3fbdSmrg	unsigned char tmp, tmp2 = 0x00;
57340e3fbdSmrg	int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
58340e3fbdSmrg
59340e3fbdSmrg	outb(vgaCRIndex, 0x55);
60340e3fbdSmrg	tmp = inb(vgaCRReg) & 0xfc;
61340e3fbdSmrg	outb(vgaCRReg, tmp | 0x01);
62340e3fbdSmrg
63340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, reg);
64340e3fbdSmrg
65340e3fbdSmrg	if (mask != 0x00)
66340e3fbdSmrg		tmp2 = inb(IBMRGB_INDEX_DATA) & mask;
67340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, tmp2 | data);
68340e3fbdSmrg
69340e3fbdSmrg	outb(vgaCRIndex, 0x55);
70340e3fbdSmrg	outb(vgaCRReg, tmp);
71340e3fbdSmrg}
72340e3fbdSmrg
73340e3fbdSmrg
74340e3fbdSmrgstatic unsigned char S3InIBMRGBIndReg(ScrnInfoPtr pScrn, CARD32 reg)
75340e3fbdSmrg{
76340e3fbdSmrg	S3Ptr pS3 = S3PTR(pScrn);
77340e3fbdSmrg	unsigned char tmp, ret;
78340e3fbdSmrg	int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
79340e3fbdSmrg
80340e3fbdSmrg	outb(vgaCRIndex, 0x55);
81340e3fbdSmrg	tmp = inb(vgaCRReg) & 0xfc;
82340e3fbdSmrg	outb(vgaCRReg, tmp | 0x01);
83340e3fbdSmrg
84340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, reg);
85340e3fbdSmrg	ret = inb(IBMRGB_INDEX_DATA);
86340e3fbdSmrg
87340e3fbdSmrg	outb(vgaCRIndex, 0x55);
88340e3fbdSmrg	outb(vgaCRReg, tmp);
89340e3fbdSmrg
90340e3fbdSmrg	return ret;
91340e3fbdSmrg}
92340e3fbdSmrg
93340e3fbdSmrg
94340e3fbdSmrgstatic void S3IBMWriteAddress(ScrnInfoPtr pScrn, CARD32 index)
95340e3fbdSmrg{
96340e3fbdSmrg	outb(IBMRGB_WRITE_ADDR, index);
97340e3fbdSmrg}
98340e3fbdSmrg
99340e3fbdSmrgstatic void S3IBMWriteData(ScrnInfoPtr pScrn, unsigned char data)
100340e3fbdSmrg{
101340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, data);
102340e3fbdSmrg}
103340e3fbdSmrg
104340e3fbdSmrgstatic void S3IBMReadAddress(ScrnInfoPtr pScrn, CARD32 index)
105340e3fbdSmrg{
106340e3fbdSmrg	outb(IBMRGB_READ_ADDR, index);
107340e3fbdSmrg}
108340e3fbdSmrg
109340e3fbdSmrgstatic unsigned char S3IBMReadData(ScrnInfoPtr pScrn)
110340e3fbdSmrg{
111340e3fbdSmrg	return inb(IBMRGB_RAMDAC_DATA);
112340e3fbdSmrg}
113340e3fbdSmrg
114340e3fbdSmrg
115340e3fbdSmrgBool S3ProbeIBMramdac(ScrnInfoPtr pScrn)
116340e3fbdSmrg{
117340e3fbdSmrg	S3Ptr pS3 = S3PTR(pScrn);
118340e3fbdSmrg
119340e3fbdSmrg	if (pS3->Chipset != PCI_CHIP_968)
120340e3fbdSmrg		return FALSE;
121340e3fbdSmrg
122340e3fbdSmrg	pS3->RamDacRec = RamDacCreateInfoRec();
123340e3fbdSmrg	pS3->RamDacRec->ReadDAC = S3InIBMRGBIndReg;
124340e3fbdSmrg	pS3->RamDacRec->WriteDAC = S3OutIBMRGBIndReg;
125340e3fbdSmrg	pS3->RamDacRec->ReadAddress = S3IBMReadAddress;
126340e3fbdSmrg	pS3->RamDacRec->WriteAddress = S3IBMWriteAddress;
127340e3fbdSmrg	pS3->RamDacRec->ReadData = S3IBMReadData;
128340e3fbdSmrg	pS3->RamDacRec->WriteData = S3IBMWriteData;
129340e3fbdSmrg	pS3->RamDacRec->LoadPalette = NULL;
130340e3fbdSmrg
131340e3fbdSmrg	if (!RamDacInit(pScrn, pS3->RamDacRec)) {
132340e3fbdSmrg		RamDacDestroyInfoRec(pS3->RamDacRec);
133340e3fbdSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "RamDacInit failed\n");
134340e3fbdSmrg		return FALSE;
135340e3fbdSmrg	}
136340e3fbdSmrg
137340e3fbdSmrg	pS3->RamDac = IBMramdacProbe(pScrn, S3IBMRamdacs);
138340e3fbdSmrg	if (pS3->RamDac)
139340e3fbdSmrg		return TRUE;
140340e3fbdSmrg
141340e3fbdSmrg	return FALSE;
142340e3fbdSmrg}
143340e3fbdSmrg
144340e3fbdSmrgstatic void S3ProgramIBMRGBClock(ScrnInfoPtr pScrn, int clk, unsigned char m,
145340e3fbdSmrg			  unsigned char n, unsigned char df)
146340e3fbdSmrg{
147340e3fbdSmrg	S3OutIBMRGBIndReg(pScrn, IBMRGB_misc_clock, ~1, 1);
148340e3fbdSmrg
149340e3fbdSmrg	S3OutIBMRGBIndReg(pScrn, IBMRGB_m0+2*clk, 0, (df<<6)|(m&0x3f));
150340e3fbdSmrg	S3OutIBMRGBIndReg(pScrn, IBMRGB_n0+2*clk, 0, n);
151340e3fbdSmrg
152340e3fbdSmrg	S3OutIBMRGBIndReg(pScrn, IBMRGB_pll_ctrl2, 0xf0, clk);
153340e3fbdSmrg	S3OutIBMRGBIndReg(pScrn, IBMRGB_pll_ctrl1, 0xf8, 3);
154340e3fbdSmrg}
155340e3fbdSmrg
156340e3fbdSmrg
157340e3fbdSmrgstatic void S3IBMRGBSetClock(ScrnInfoPtr pScrn, long freq, int clk, long dacspeed,
158340e3fbdSmrg		      long fref)
159340e3fbdSmrg{
160340e3fbdSmrg	volatile double ffreq, fdacspeed, ffref;
161340e3fbdSmrg	volatile int df, n, m, max_n, min_df;
162340e3fbdSmrg	volatile int best_m=69, best_n=17, best_df=0;
163340e3fbdSmrg	volatile double diff, mindiff;
164340e3fbdSmrg
165340e3fbdSmrg#define FREQ_MIN	16250
166340e3fbdSmrg#define FREQ_MAX	dacspeed
167340e3fbdSmrg
168340e3fbdSmrg	if (freq < FREQ_MIN)
169340e3fbdSmrg		ffreq = FREQ_MIN / 1000.0;
170340e3fbdSmrg	else if (freq > FREQ_MAX)
171340e3fbdSmrg		ffreq = FREQ_MAX / 1000.0;
172340e3fbdSmrg	else
173340e3fbdSmrg		ffreq = freq / 1000.0;
174340e3fbdSmrg
175340e3fbdSmrg	fdacspeed = dacspeed / 1e3;
176340e3fbdSmrg	ffref = fref / 1e3;
177340e3fbdSmrg
178340e3fbdSmrg	ffreq /= ffref;
179340e3fbdSmrg	ffreq *= 16;
180340e3fbdSmrg	mindiff = ffreq;
181340e3fbdSmrg
182340e3fbdSmrg	if (freq <= dacspeed/4)
183340e3fbdSmrg		min_df = 0;
184340e3fbdSmrg	else if (freq <= dacspeed/2)
185340e3fbdSmrg		min_df = 1;
186340e3fbdSmrg	else
187340e3fbdSmrg		min_df = 2;
188340e3fbdSmrg
189340e3fbdSmrg	for (df=0; df<4; df++) {
190340e3fbdSmrg		ffreq /= 2;
191340e3fbdSmrg		mindiff /= 2;
192340e3fbdSmrg		if (df < min_df)
193340e3fbdSmrg			continue;
194340e3fbdSmrg
195340e3fbdSmrg		if (df < 3)
196340e3fbdSmrg			max_n = fref / 1000 / 2;
197340e3fbdSmrg		else
198340e3fbdSmrg			max_n = fref / 1000;
199340e3fbdSmrg		if (max_n > 31)
200340e3fbdSmrg			max_n = 31;
201340e3fbdSmrg
202340e3fbdSmrg		for (n=2; n <= max_n; n++) {
203340e3fbdSmrg			m = (int)(ffreq * n + 0.5) - 65;
204340e3fbdSmrg			if (m < 0)
205340e3fbdSmrg				m = 0;
206340e3fbdSmrg			else if (m > 63)
207340e3fbdSmrg				m = 63;
208340e3fbdSmrg			diff = (m+65.0)/n-ffreq;
209340e3fbdSmrg			if (diff < 0)
210340e3fbdSmrg				diff = -diff;
211340e3fbdSmrg			if (diff < mindiff) {
212340e3fbdSmrg				mindiff = diff;
213340e3fbdSmrg				best_n = n;
214340e3fbdSmrg				best_m = m;
215340e3fbdSmrg				best_df = df;
216340e3fbdSmrg			}
217340e3fbdSmrg		}
218340e3fbdSmrg	}
219340e3fbdSmrg
220340e3fbdSmrg	S3ProgramIBMRGBClock(pScrn, clk, best_m, best_n, best_df);
221340e3fbdSmrg}
222340e3fbdSmrg
223340e3fbdSmrgvoid S3IBMRGB_Restore(ScrnInfoPtr pScrn)
224340e3fbdSmrg{
225340e3fbdSmrg	S3Ptr pS3 = S3PTR(pScrn);
226340e3fbdSmrg	S3RegPtr restore = &pS3->SavedRegs;
227340e3fbdSmrg	int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
228340e3fbdSmrg	int i;
229340e3fbdSmrg
230340e3fbdSmrg	for(i=0; i<0x100; i++)
231340e3fbdSmrg		S3OutIBMRGBIndReg(pScrn, i, 0, restore->dacregs[i]);
232340e3fbdSmrg
233340e3fbdSmrg	outb(vgaCRIndex, 0x22);
234340e3fbdSmrg	outb(vgaCRReg, restore->dacregs[0x100]);
235340e3fbdSmrg}
236340e3fbdSmrg
237340e3fbdSmrg
238340e3fbdSmrgvoid S3IBMRGB_Save(ScrnInfoPtr pScrn)
239340e3fbdSmrg{
240340e3fbdSmrg	S3Ptr pS3 = S3PTR(pScrn);
241340e3fbdSmrg	S3RegPtr save = &pS3->SavedRegs;
242340e3fbdSmrg	int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
243340e3fbdSmrg	int i;
244340e3fbdSmrg
245340e3fbdSmrg	for (i=0; i<0x100; i++)
246340e3fbdSmrg		save->dacregs[i] = S3InIBMRGBIndReg(pScrn, i);
247340e3fbdSmrg
248340e3fbdSmrg	outb(vgaCRIndex, 0x22);
249340e3fbdSmrg	save->dacregs[0x100] = inb(vgaCRReg);
250340e3fbdSmrg}
251340e3fbdSmrg
252340e3fbdSmrg
253340e3fbdSmrgvoid S3IBMRGB_PreInit(ScrnInfoPtr pScrn)
254340e3fbdSmrg{
255340e3fbdSmrg	S3Ptr pS3 = S3PTR(pScrn);
256340e3fbdSmrg	int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
257340e3fbdSmrg	unsigned char cr55, tmp;
258340e3fbdSmrg
259340e3fbdSmrg	outb(vgaCRIndex, 0x43);
260340e3fbdSmrg	tmp = inb(vgaCRReg);
261340e3fbdSmrg	outb(vgaCRReg, tmp & ~0x02);
262340e3fbdSmrg
263340e3fbdSmrg	outb(vgaCRIndex, 0x55);
264340e3fbdSmrg	cr55 = inb(vgaCRReg);
265340e3fbdSmrg	outb(vgaCRReg, (cr55 & ~0x03) | 0x01);	/* set rs2 */
266340e3fbdSmrg
267340e3fbdSmrg	tmp = inb(IBMRGB_INDEX_CONTROL);
268340e3fbdSmrg	outb(IBMRGB_INDEX_CONTROL, tmp & ~1);
269340e3fbdSmrg	outb(IBMRGB_INDEX_HIGH, 0);
270340e3fbdSmrg
271340e3fbdSmrg	outb(vgaCRIndex, 0x55);
272340e3fbdSmrg	outb(vgaCRReg, cr55 & ~0x03);
273340e3fbdSmrg
274340e3fbdSmrg	{
275340e3fbdSmrg		int m, n, df, mclk=0;
276340e3fbdSmrg
277340e3fbdSmrg		m = S3InIBMRGBIndReg(pScrn, IBMRGB_sysclk_vco_div);
278340e3fbdSmrg		n = S3InIBMRGBIndReg(pScrn, IBMRGB_sysclk_ref_div) & 0x1f;
279340e3fbdSmrg		df = m >> 6;
280340e3fbdSmrg		m &= 0x3f;
281340e3fbdSmrg		if (!n) {
282340e3fbdSmrg			m = 0;
283340e3fbdSmrg			n = 1;
284340e3fbdSmrg		}
285340e3fbdSmrg		mclk = ((pS3->RefClock*100 * (m+65)) / n / (8 >> df) + 50) / 100;
286340e3fbdSmrg		pS3->mclk = mclk;
287340e3fbdSmrg		xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "MCLK %1.3f MHz\n",
288340e3fbdSmrg			   mclk / 1000.0);
289340e3fbdSmrg	}
290340e3fbdSmrg}
291340e3fbdSmrg
292340e3fbdSmrg
293340e3fbdSmrgvoid S3IBMRGB_Init(ScrnInfoPtr pScrn, DisplayModePtr mode)
294340e3fbdSmrg{
295340e3fbdSmrg	S3Ptr pS3 = S3PTR(pScrn);
296340e3fbdSmrg	unsigned char tmp, blank;
297340e3fbdSmrg	int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
298340e3fbdSmrg
299340e3fbdSmrg	S3IBMRGBSetClock(pScrn, mode->Clock, 2, pS3->MaxClock,
300340e3fbdSmrg			 pS3->RefClock);
301340e3fbdSmrg
302340e3fbdSmrg	outb(0x3c4, 1);
303340e3fbdSmrg	blank = inb(0x3c5);
304340e3fbdSmrg	outb(0x3c5, blank | 0x20);
305340e3fbdSmrg
306340e3fbdSmrg	S3OutIBMRGBIndReg(pScrn, IBMRGB_misc_clock, 0xf0, 0x03);
307340e3fbdSmrg	S3OutIBMRGBIndReg(pScrn, IBMRGB_sync, 0, 0);
308340e3fbdSmrg	S3OutIBMRGBIndReg(pScrn, IBMRGB_hsync_pos, 0, 0);
309340e3fbdSmrg	S3OutIBMRGBIndReg(pScrn, IBMRGB_pwr_mgmt, 0, 0);
310340e3fbdSmrg	S3OutIBMRGBIndReg(pScrn, IBMRGB_dac_op, ~8, 0);
311340e3fbdSmrg	S3OutIBMRGBIndReg(pScrn, IBMRGB_dac_op, ~2, 2);
312340e3fbdSmrg	S3OutIBMRGBIndReg(pScrn, IBMRGB_pal_ctrl, 0, 0);
313340e3fbdSmrg	S3OutIBMRGBIndReg(pScrn, IBMRGB_misc1, ~0x43, 1);
314340e3fbdSmrg	S3OutIBMRGBIndReg(pScrn, IBMRGB_misc2, 0, 0x47);
315340e3fbdSmrg
316340e3fbdSmrg	outb(vgaCRIndex, 0x22);
317340e3fbdSmrg	tmp = inb(vgaCRReg);
318340e3fbdSmrg	if (pS3->s3Bpp == 1)
319340e3fbdSmrg		outb(vgaCRReg, tmp | 8);
320340e3fbdSmrg	else
321340e3fbdSmrg		outb(vgaCRReg, tmp & ~8);
322340e3fbdSmrg
323340e3fbdSmrg	outb(vgaCRIndex, 0x65);
324340e3fbdSmrg	outb(vgaCRReg, 0x00);	/* ! 528 */
325340e3fbdSmrg
326340e3fbdSmrg	outb(vgaCRIndex, 0x40);
327340e3fbdSmrg	outb(vgaCRReg, 0x11);
328340e3fbdSmrg	outb(vgaCRIndex, 0x55);
329340e3fbdSmrg	outb(vgaCRReg, 0x00);
330340e3fbdSmrg
331340e3fbdSmrg	switch (pScrn->depth) {
332340e3fbdSmrg	case 8:
333340e3fbdSmrg		S3OutIBMRGBIndReg(pScrn, IBMRGB_pix_fmt, 0xf8, 3);
334340e3fbdSmrg		S3OutIBMRGBIndReg(pScrn, IBMRGB_8bpp, 0, 0);
335340e3fbdSmrg		break;
336340e3fbdSmrg	case 15:
337340e3fbdSmrg		S3OutIBMRGBIndReg(pScrn, IBMRGB_pix_fmt, 0xf8, 4);
338340e3fbdSmrg		S3OutIBMRGBIndReg(pScrn, IBMRGB_16bpp, 0, 0xc0);
339340e3fbdSmrg		break;
340340e3fbdSmrg	case 16:
341340e3fbdSmrg		S3OutIBMRGBIndReg(pScrn, IBMRGB_pix_fmt, 0xf8, 4);
342340e3fbdSmrg		S3OutIBMRGBIndReg(pScrn, IBMRGB_16bpp, 0, 0xc2);
343340e3fbdSmrg		break;
344340e3fbdSmrg	}
345340e3fbdSmrg
346340e3fbdSmrg	outb(vgaCRIndex, 0x66);
347340e3fbdSmrg	tmp = inb(vgaCRReg) & 0xf8;
348340e3fbdSmrg	outb(vgaCRReg, tmp);
349340e3fbdSmrg
350340e3fbdSmrg	outb(vgaCRIndex, 0x58);
351340e3fbdSmrg	tmp = (inb(vgaCRReg) & 0xbf) | 0x40;
352340e3fbdSmrg	outb(vgaCRReg, tmp);
353340e3fbdSmrg
354340e3fbdSmrg	outb(vgaCRIndex, 0x67);
355340e3fbdSmrg	outb(vgaCRReg, 0x11);
356340e3fbdSmrg
357340e3fbdSmrg	switch (pScrn->bitsPerPixel) {
358340e3fbdSmrg	case 8:
359340e3fbdSmrg		tmp = 0x21;
360340e3fbdSmrg		break;
361340e3fbdSmrg	case 16:
362340e3fbdSmrg		tmp = 0x10;
363340e3fbdSmrg		break;
364340e3fbdSmrg	}
365340e3fbdSmrg	outb(vgaCRIndex, 0x6d);
366340e3fbdSmrg	outb(vgaCRReg, tmp);
367340e3fbdSmrg
368340e3fbdSmrg	outb(0x3c4, 1);
369340e3fbdSmrg	outb(0x3c5, blank);
370340e3fbdSmrg}
371340e3fbdSmrg
372340e3fbdSmrg
373340e3fbdSmrg/* hardware cursor */
374340e3fbdSmrg
375340e3fbdSmrgstatic void S3IBMRGBSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
376340e3fbdSmrg{
377340e3fbdSmrg	S3Ptr pS3 = S3PTR(pScrn);
378340e3fbdSmrg	int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
379340e3fbdSmrg	unsigned char tmp;
380340e3fbdSmrg
381340e3fbdSmrg	/* unlock sys regs */
382340e3fbdSmrg	outb(vgaCRIndex, 0x39);
383340e3fbdSmrg	outb(vgaCRReg, 0xa5);
384340e3fbdSmrg
385340e3fbdSmrg	outb(vgaCRIndex, 0x55);
386340e3fbdSmrg	tmp = inb(vgaCRReg) & 0xfc;
387340e3fbdSmrg	outb(vgaCRReg, tmp | 0x01);
388340e3fbdSmrg
389340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col1_r);
390340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, (bg & 0x00ff0000) >> 16);
391340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col1_g);
392340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, (bg & 0x0000ff00) >> 8);
393340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col1_b);
394340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, (bg & 0x000000ff));
395340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col2_r);
396340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, (fg & 0x00ff0000) >> 16);
397340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col2_g);
398340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, (fg & 0x0000ff00) >> 8);
399340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, IBMRGB_curs_col2_b);
400340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, (fg & 0x000000ff));
401340e3fbdSmrg
402340e3fbdSmrg	outb(vgaCRReg, tmp);
403340e3fbdSmrg}
404340e3fbdSmrg
405340e3fbdSmrg
406340e3fbdSmrgstatic void S3IBMRGBSetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
407340e3fbdSmrg{
408340e3fbdSmrg	S3Ptr pS3 = S3PTR(pScrn);
409340e3fbdSmrg	int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
410340e3fbdSmrg	unsigned char tmp;
411340e3fbdSmrg
412340e3fbdSmrg	/* unlock sys regs */
413340e3fbdSmrg	outb(vgaCRIndex, 0x39);
414340e3fbdSmrg	outb(vgaCRReg, 0xa5);
415340e3fbdSmrg
416340e3fbdSmrg	outb(vgaCRIndex, 0x55);
417340e3fbdSmrg	tmp = inb(vgaCRReg) & 0xfc;
418340e3fbdSmrg	outb(vgaCRReg, tmp | 0x01);
419340e3fbdSmrg
420340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, IBMRGB_curs_xl);
421340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, x);
422340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, IBMRGB_curs_xh);
423340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, x >> 8);
424340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, IBMRGB_curs_yl);
425340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, y);
426340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, IBMRGB_curs_yh);
427340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, y >> 8);
428340e3fbdSmrg
429340e3fbdSmrg	outb(vgaCRReg, tmp);
430340e3fbdSmrg}
431340e3fbdSmrg
432340e3fbdSmrg
433340e3fbdSmrgstatic void S3IBMRGBHideCursor(ScrnInfoPtr pScrn)
434340e3fbdSmrg{
435340e3fbdSmrg	S3Ptr pS3 = S3PTR(pScrn);
436340e3fbdSmrg	int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
437340e3fbdSmrg
438340e3fbdSmrg	/* unlock sys regs */
439340e3fbdSmrg	outb(vgaCRIndex, 0x39);
440340e3fbdSmrg	outb(vgaCRReg, 0xa5);
441340e3fbdSmrg
442340e3fbdSmrg	S3OutIBMRGBIndReg(pScrn, IBMRGB_curs, ~3, 0x00);
443340e3fbdSmrg}
444340e3fbdSmrg
445340e3fbdSmrg
446340e3fbdSmrgstatic void S3IBMRGBShowCursor(ScrnInfoPtr pScrn)
447340e3fbdSmrg{
448340e3fbdSmrg	S3Ptr pS3 = S3PTR(pScrn);
449340e3fbdSmrg	int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
450340e3fbdSmrg	unsigned char tmp;
451340e3fbdSmrg
452340e3fbdSmrg	/* unlock sys regs */
453340e3fbdSmrg	outb(vgaCRIndex, 0x39);
454340e3fbdSmrg	outb(vgaCRReg, 0xa5);
455340e3fbdSmrg
456340e3fbdSmrg	outb(vgaCRIndex, 0x55);
457340e3fbdSmrg	tmp = (inb(vgaCRReg) & 0xdf) | 0x20;
458340e3fbdSmrg	outb(vgaCRReg, tmp);
459340e3fbdSmrg
460340e3fbdSmrg	outb(vgaCRIndex, 0x45);
461340e3fbdSmrg	tmp = inb(vgaCRReg) & ~0x20;
462340e3fbdSmrg	outb(vgaCRReg, tmp);
463340e3fbdSmrg
464340e3fbdSmrg	S3OutIBMRGBIndReg(pScrn, IBMRGB_curs, 0, 0x27);
465340e3fbdSmrg}
466340e3fbdSmrg
467340e3fbdSmrg
468340e3fbdSmrgstatic void S3IBMRGBLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *image)
469340e3fbdSmrg{
470340e3fbdSmrg	S3Ptr pS3 = S3PTR(pScrn);
471340e3fbdSmrg	int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
472340e3fbdSmrg	unsigned char tmp, tmp2;
473340e3fbdSmrg	register int i;
474340e3fbdSmrg
475340e3fbdSmrg	/* unlock sys regs */
476340e3fbdSmrg	outb(vgaCRIndex, 0x39);
477340e3fbdSmrg	outb(vgaCRReg, 0xa5);
478340e3fbdSmrg
479340e3fbdSmrg	outb(vgaCRIndex, 0x55);
480340e3fbdSmrg	tmp = inb(vgaCRReg) & 0xfc;
481340e3fbdSmrg	outb(vgaCRReg, tmp | 0x01);
482340e3fbdSmrg
483340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, IBMRGB_curs_hot_x);
484340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, 0);
485340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, IBMRGB_curs_hot_y);
486340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, 0);
487340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, IBMRGB_curs_xl);
488340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, 0xff);
489340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, IBMRGB_curs_xh);
490340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, 0x7f);
491340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, IBMRGB_curs_yl);
492340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, 0xff);
493340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, IBMRGB_curs_yh);
494340e3fbdSmrg	outb(IBMRGB_INDEX_DATA, 0x7f);
495340e3fbdSmrg
496340e3fbdSmrg	tmp2 = inb(IBMRGB_INDEX_CONTROL) & 0xfe;
497340e3fbdSmrg	outb(IBMRGB_INDEX_CONTROL, tmp2 | 1);	/* enable auto increment */
498340e3fbdSmrg
499340e3fbdSmrg	outb(IBMRGB_INDEX_HIGH, (unsigned char) (IBMRGB_curs_array >> 8));
500340e3fbdSmrg	outb(IBMRGB_INDEX_LOW, (unsigned char) (IBMRGB_curs_array));
501340e3fbdSmrg
502340e3fbdSmrg	for (i=0; i<1024; i++)
503340e3fbdSmrg		outb(IBMRGB_INDEX_DATA, *image++);
504340e3fbdSmrg
505340e3fbdSmrg	outb(IBMRGB_INDEX_HIGH, 0);
506340e3fbdSmrg	outb(IBMRGB_INDEX_CONTROL, tmp2);	/* disable auto increment */
507340e3fbdSmrg	outb(vgaCRIndex, 0x55);
508340e3fbdSmrg	outb(vgaCRReg, tmp);
509340e3fbdSmrg}
510340e3fbdSmrg
511340e3fbdSmrg
512340e3fbdSmrgstatic Bool S3IBMRGBUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
513340e3fbdSmrg{
514b27e1915Smrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
515340e3fbdSmrg	S3Ptr pS3 = S3PTR(pScrn);
516340e3fbdSmrg	return (pS3->hwCursor);
517340e3fbdSmrg}
518340e3fbdSmrg
519340e3fbdSmrg
520340e3fbdSmrgBool S3IBMRGB_CursorInit(ScreenPtr pScreen)
521340e3fbdSmrg{
522b27e1915Smrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
523340e3fbdSmrg	S3Ptr pS3 = S3PTR(pScrn);
524340e3fbdSmrg	xf86CursorInfoPtr pCurs;
525340e3fbdSmrg
526340e3fbdSmrg	if (!(pCurs = pS3->pCurs = xf86CreateCursorInfoRec()))
527340e3fbdSmrg		return FALSE;
528340e3fbdSmrg
529340e3fbdSmrg	pCurs->MaxWidth = 64;
530340e3fbdSmrg	pCurs->MaxHeight = 64;
531340e3fbdSmrg	pCurs->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
532340e3fbdSmrg		       HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
533340e3fbdSmrg		       HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
534340e3fbdSmrg		       HARDWARE_CURSOR_NIBBLE_SWAPPED |
535340e3fbdSmrg		       HARDWARE_CURSOR_BIT_ORDER_MSBFIRST;
536340e3fbdSmrg
537340e3fbdSmrg	pCurs->SetCursorColors = S3IBMRGBSetCursorColors;
538340e3fbdSmrg	pCurs->SetCursorPosition = S3IBMRGBSetCursorPosition;
539340e3fbdSmrg	pCurs->LoadCursorImage = S3IBMRGBLoadCursorImage;
540340e3fbdSmrg	pCurs->HideCursor = S3IBMRGBHideCursor;
541340e3fbdSmrg	pCurs->ShowCursor = S3IBMRGBShowCursor;
542340e3fbdSmrg	pCurs->UseHWCursor = S3IBMRGBUseHWCursor;
543340e3fbdSmrg
544340e3fbdSmrg	return xf86InitCursor(pScreen, pCurs);
545340e3fbdSmrg}
546340e3fbdSmrg
547340e3fbdSmrg
548