s3_Ti.c revision a9060c92
1/*
2 *      Copyright 2001  Ani Joshi <ajoshi@unixbox.com>
3 *
4 *      XFree86 4.x driver for S3 chipsets
5 *
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that copyright
10 * notice and this permission notice appear in supporting documentation and
11 * that the name of Ani Joshi not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission.  Ani Joshi makes no representations
14 * about the suitability of this software for any purpose.  It is provided
15 * "as-is" without express or implied warranty.
16 *
17 * ANI JOSHI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19 * EVENT SHALL ANI JOSHI BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23 * PERFORMANCE OF THIS SOFTWARE.
24 *
25 *
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include "xf86.h"
33#include "xf86_OSproc.h"
34#include <X11/Xos.h>
35
36#include "compiler.h"
37
38#include "TI.h"
39
40#include "s3.h"
41
42
43#define TI_WRITE_ADDR           0x3C8   /* CR55 low bit == 0 */
44#define TI_RAMDAC_DATA          0x3C9   /* CR55 low bit == 0 */
45#define TI_PIXEL_MASK           0x3C6   /* CR55 low bit == 0 */
46#define TI_READ_ADDR            0x3C7   /* CR55 low bit == 0 */
47#define TI_INDEX_REG            0x3C6   /* CR55 low bit == 1 */
48#define TI_DATA_REG             0x3C7   /* CR55 low bit == 1 */
49
50#define	TIDAC_output_clock_select	0x1b
51#define	TIDAC_auxiliary_ctrl		0x29
52#define	TIDAC_general_io_ctrl		0x2a
53#define TIDAC_general_io_data		0x2b
54#define TIDAC_cursor_color_0_red	0x23
55#define TIDAC_cursor_color_0_green	0x24
56#define TIDAC_cursor_color_0_blue	0x25
57#define TIDAC_cursor_color_1_red	0x26
58#define TIDAC_cursor_color_1_green	0x27
59#define TIDAC_cursor_color_1_blue	0x28
60#define TIDAC_cursor_x_low		0x00
61#define TIDAC_cursor_x_high		0x01
62#define TIDAC_cursor_y_low		0x02
63#define TIDAC_cursor_y_high		0x03
64#define TIDAC_cursor_ram_addr_low	0x08
65#define TIDAC_cursor_ram_addr_high	0x09
66#define TIDAC_cursor_ram_data		0x0a
67
68
69#define TI_REF_FREQ             14.31818  /* 3025 only */
70
71#undef  FREQ_MIN
72#define FREQ_MIN   12000
73#define FREQ_MAX  220000
74
75
76
77void S3OutTiIndReg(ScrnInfoPtr pScrn, CARD32 reg, unsigned char mask,
78		   unsigned char data)
79{
80	S3Ptr pS3 = S3PTR(pScrn);
81	int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
82	unsigned char tmp, tmp1, tmp2 = 0x00;
83
84	outb(vgaCRIndex, 0x55);
85	tmp = inb(vgaCRReg) & 0xfc;
86	outb(vgaCRReg, tmp | 0x01);
87	tmp1 = inb(TI_INDEX_REG);
88	outb(TI_INDEX_REG, reg);
89
90	if (mask != 0x00)
91		tmp2 = inb(TI_DATA_REG) & mask;
92	outb(TI_DATA_REG, tmp2 | data);
93
94	outb(TI_INDEX_REG, tmp1);
95	outb(vgaCRReg, tmp);
96}
97
98
99static unsigned char S3InTiIndReg(ScrnInfoPtr pScrn, CARD32 reg)
100{
101	S3Ptr pS3 = S3PTR(pScrn);
102	int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
103	unsigned char tmp, tmp1, ret;
104
105	outb(vgaCRIndex, 0x55);
106	tmp = inb(vgaCRReg) & 0xfc;
107	outb(vgaCRReg, tmp | 0x01);
108	tmp1 = inb(TI_INDEX_REG);
109	outb(TI_INDEX_REG, reg);
110
111	ret = inb(TI_DATA_REG);
112
113	outb(TI_INDEX_REG, tmp1);
114	outb(vgaCRReg, tmp);
115
116	return ret;
117}
118
119
120Bool S3TiDACProbe(ScrnInfoPtr pScrn)
121{
122	S3Ptr pS3 = S3PTR(pScrn);
123	int found = 0;
124	int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
125	unsigned char cr55, cr45, cr43, cr5c;
126	unsigned char TIndx, TIndx2, TIdata;
127
128	if (!S3_964_SERIES())
129		return FALSE;
130
131	outb(vgaCRIndex, 0x43);
132	cr43 = inb(vgaCRReg);
133	outb(vgaCRReg, cr43 & ~0x02);
134
135	outb(vgaCRIndex, 0x45);
136	cr45 = inb(vgaCRReg);
137
138	outb(vgaCRIndex, 0x55);
139	cr55 = inb(vgaCRReg);
140	outb(vgaCRReg, (cr55 & 0xfc) | 0x01);
141
142	TIndx = inb(TI_INDEX_REG);
143	outb(TI_INDEX_REG, TIDAC_id);
144	if(inb(TI_DATA_REG) == 0x20) {
145		found = TI3020_RAMDAC;
146		cr43 &= ~0x02;
147		cr45 &= ~0x20;
148	} else {
149		outb(vgaCRIndex, 0x5c);
150		cr5c = inb(vgaCRReg);
151		outb(vgaCRReg, cr5c & 0xdf);
152		TIndx2 = inb(TI_INDEX_REG);
153		outb(TI_INDEX_REG, TIDAC_ind_curs_ctrl);
154		TIdata = inb(TI_DATA_REG);
155		outb(TI_DATA_REG, TIdata & 0x7f);
156
157		outb(TI_INDEX_REG, TIDAC_id);
158		if (inb(TI_DATA_REG) == 0x25) {
159			found = TI3025_RAMDAC;
160			cr43 &= ~0x02;
161			cr45 &= ~0x20;
162		}
163
164		outb(TI_INDEX_REG, TIDAC_ind_curs_ctrl);
165		outb(TI_DATA_REG, TIdata);
166		outb(TI_INDEX_REG, TIndx2);
167		outb(vgaCRIndex, 0x5c);
168		outb(vgaCRReg, cr5c);
169	}
170
171	outb(TI_INDEX_REG, TIndx);
172	outb(vgaCRIndex, 0x55);
173	outb(vgaCRReg, cr55);
174
175	outb(vgaCRIndex, 0x45);
176	outb(vgaCRReg, cr45);
177
178	outb(vgaCRIndex, 0x43);
179	outb(vgaCRReg, cr43);
180
181	if (found) {
182		RamDacInit(pScrn, pS3->RamDacRec);
183		pS3->RamDac = RamDacHelperCreateInfoRec();
184		pS3->RamDac->RamDacType = found;
185		return TRUE;
186	}
187
188	return FALSE;
189}
190
191
192void S3TiDAC_Save(ScrnInfoPtr pScrn)
193{
194	S3Ptr pS3 = S3PTR(pScrn);
195	S3RegPtr save = &pS3->SavedRegs;
196	int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
197
198	if (pS3->RamDac->RamDacType == TI3025_RAMDAC) {
199		unsigned char cr5c;
200
201		outb(vgaCRIndex, 0x5c);
202		cr5c = inb(vgaCRReg);
203		outb(vgaCRReg, cr5c & 0xdf);
204
205		save->dacregs[TIDAC_ind_curs_ctrl] =
206				 S3InTiIndReg(pScrn, TIDAC_ind_curs_ctrl);
207		S3OutTiIndReg(pScrn, TIDAC_ind_curs_ctrl, 0x7f, 0x00);
208	}
209
210	save->dacregs[TIDAC_true_color_ctrl] =
211			S3InTiIndReg(pScrn, TIDAC_true_color_ctrl);
212	save->dacregs[TIDAC_multiplex_ctrl] =
213			S3InTiIndReg(pScrn, TIDAC_multiplex_ctrl);
214	save->dacregs[TIDAC_clock_select] =
215			S3InTiIndReg(pScrn, TIDAC_clock_select);
216	save->dacregs[TIDAC_output_clock_select] =
217			S3InTiIndReg(pScrn, TIDAC_output_clock_select);
218	save->dacregs[TIDAC_general_ctrl] =
219			S3InTiIndReg(pScrn, TIDAC_general_ctrl);
220	save->dacregs[TIDAC_auxiliary_ctrl] =
221			S3InTiIndReg(pScrn, TIDAC_auxiliary_ctrl);
222	S3OutTiIndReg(pScrn, TIDAC_general_io_ctrl, 0x00, 0x1f);
223	save->dacregs[TIDAC_general_io_data] =
224			S3InTiIndReg(pScrn, TIDAC_general_io_data);
225
226	if (pS3->RamDac->RamDacType == TI3025_RAMDAC) {
227		save->dacregs[0x0e] = S3InTiIndReg(pScrn, 0x0e);
228		save->dacregs[TIDAC_misc_ctrl] =
229			S3InTiIndReg(pScrn, TIDAC_misc_ctrl);
230		S3OutTiIndReg(pScrn, TIDAC_pll_addr, 0x00, 0x00);
231		save->dacregs[0x40] = S3InTiIndReg(pScrn, TIDAC_pll_pixel_data);
232		S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00,
233			      save->dacregs[0x40]);
234		save->dacregs[0x41] = S3InTiIndReg(pScrn, TIDAC_pll_pixel_data);
235		S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00,
236			      save->dacregs[0x41]);
237		save->dacregs[0x42] = S3InTiIndReg(pScrn, TIDAC_pll_pixel_data);
238		S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00,
239			      save->dacregs[0x42]);
240		save->dacregs[0x43] = S3InTiIndReg(pScrn, TIDAC_pll_memory_data);
241		S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00,
242			      save->dacregs[0x43]);
243		save->dacregs[0x44] = S3InTiIndReg(pScrn, TIDAC_pll_memory_data);
244		S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00,
245			      save->dacregs[0x44]);
246		save->dacregs[0x45] = S3InTiIndReg(pScrn, TIDAC_pll_memory_data);
247		S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00,
248			      save->dacregs[0x45]);
249		save->dacregs[0x46] = S3InTiIndReg(pScrn, TIDAC_pll_loop_data);
250		S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00,
251			      save->dacregs[0x46]);
252		save->dacregs[0x47] = S3InTiIndReg(pScrn, TIDAC_pll_loop_data);
253		S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00,
254			      save->dacregs[0x47]);
255		save->dacregs[0x48] = S3InTiIndReg(pScrn, TIDAC_pll_loop_data);
256		S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00,
257			      save->dacregs[0x48]);
258	}
259}
260
261
262void S3TiDAC_Restore(ScrnInfoPtr pScrn)
263{
264	S3Ptr pS3 = S3PTR(pScrn);
265	S3RegPtr restore = &pS3->SavedRegs;
266
267	S3OutTiIndReg(pScrn, TIDAC_true_color_ctrl, 0x00,
268		      restore->dacregs[TIDAC_true_color_ctrl]);
269	S3OutTiIndReg(pScrn, TIDAC_multiplex_ctrl, 0x00,
270		      restore->dacregs[TIDAC_multiplex_ctrl]);
271	S3OutTiIndReg(pScrn, TIDAC_clock_select, 0x00,
272		      restore->dacregs[TIDAC_clock_select]);
273	S3OutTiIndReg(pScrn, TIDAC_output_clock_select, 0x00,
274		      restore->dacregs[TIDAC_output_clock_select]);
275	S3OutTiIndReg(pScrn, TIDAC_general_ctrl, 0x00,
276		      restore->dacregs[TIDAC_general_ctrl]);
277	S3OutTiIndReg(pScrn, TIDAC_auxiliary_ctrl, 0x00,
278		      restore->dacregs[TIDAC_auxiliary_ctrl]);
279	S3OutTiIndReg(pScrn, TIDAC_general_io_ctrl, 0x00, 0x1f);
280	S3OutTiIndReg(pScrn, TIDAC_general_io_data, 0x00,
281		      restore->dacregs[TIDAC_general_io_data]);
282	if (pS3->RamDac->RamDacType == TI3025_RAMDAC) {
283		S3OutTiIndReg(pScrn, TIDAC_pll_addr, 0x00,
284			      restore->dacregs[TIDAC_pll_addr]);
285		S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00,
286			      restore->dacregs[0x40]);
287		S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00,
288			      restore->dacregs[0x41]);
289		S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00,
290			      restore->dacregs[0x42]);
291
292		S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00,
293			      restore->dacregs[0x43]);
294		S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00,
295			      restore->dacregs[0x44]);
296		S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00,
297			      restore->dacregs[0x45] | 0x80);
298
299		S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00,
300			      restore->dacregs[0x46]);
301		S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00,
302			      restore->dacregs[0x47]);
303		S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00,
304			      restore->dacregs[0x48]);
305
306		S3OutTiIndReg(pScrn, 0x0e, 0x00, restore->dacregs[0x0e]);
307		S3OutTiIndReg(pScrn, TIDAC_misc_ctrl, 0x00,
308			      restore->dacregs[TIDAC_misc_ctrl]);
309	}
310
311	S3OutTiIndReg(pScrn, TIDAC_ind_curs_ctrl, 0x00,
312		      restore->dacregs[TIDAC_ind_curs_ctrl]);
313}
314
315
316void S3TiDAC_PreInit(ScrnInfoPtr pScrn)
317{
318        S3Ptr pS3 = S3PTR(pScrn);
319        int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
320	int mclk, m, n, p, mcc, cr5c;
321
322	outb(vgaCRIndex, 0x5c);
323	cr5c = inb(vgaCRReg);
324	outb(vgaCRReg, cr5c & 0xdf);
325
326	S3OutTiIndReg(pScrn, TIDAC_pll_addr, 0x00, 0x00);
327	n = S3InTiIndReg(pScrn, TIDAC_pll_memory_data) & 0x7f;
328	S3OutTiIndReg(pScrn, TIDAC_pll_addr, 0x00, 0x01);
329	m = S3InTiIndReg(pScrn, TIDAC_pll_memory_data) & 0x7f;
330	S3OutTiIndReg(pScrn, TIDAC_pll_addr, 0x00, 0x02);
331	p = S3InTiIndReg(pScrn, TIDAC_pll_memory_data) & 0x03;
332	mcc = S3InTiIndReg(pScrn, TIDAC_clock_ctrl);
333	if (mcc & 0x08)
334		mcc = (mcc & 0x07) * 2 + 2;
335	else
336		mcc = 1;
337
338	mclk = ((1431818 * ((m+2) * 8)) / (n+2) / (1 << p) / mcc + 50) / 100;
339	pS3->mclk = mclk;
340     	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "MCLK %1.3f MHz\n",
341           	   mclk / 1000.0);
342
343	outb(vgaCRIndex, 0x5c);
344	outb(vgaCRReg, cr5c);
345}
346
347
348static void S3TiDACCalcNMP(long freq, int *calc_n, int *calc_m, int *calc_p)
349{
350	double ffreq;
351	int n, m, p;
352	int best_n=32, best_m=32;
353	double diff, mindiff;
354
355	if (freq < FREQ_MIN)
356		ffreq = FREQ_MIN / 1000.0;
357	else if (freq > FREQ_MAX)
358		ffreq = FREQ_MAX / 1000.0;
359	else
360		ffreq = freq / 1000.0;
361
362	for (p=0; p<4 && ffreq<110.0; p++)
363		ffreq *= 2;
364#if FREQ_MIN < 110000/8
365	if (p == 4) {
366		ffreq /= 2;
367		p--;
368	}
369#endif
370
371	ffreq /= TI_REF_FREQ;
372
373	mindiff = ffreq;
374
375	for (n=1; n<=(int)(TI_REF_FREQ/0.5 - 2); n++) {
376		m = (int)(ffreq * (n+2) / 8.0 + 0.5) - 2;
377		if (m < 1)
378			m = 1;
379		else if (m > 127)
380			m = 127;
381
382		diff = ((m+2) * 8) / (n+2.0) - ffreq;
383		if (diff < 0)
384			diff = -diff;
385
386		if (diff < mindiff) {
387			mindiff = diff;
388			best_n = n;
389			best_m = m;
390		}
391	}
392
393	*calc_n = best_n;
394   	*calc_m = best_m;
395   	*calc_p = p;
396}
397
398
399static void S3TiDACProgramClock(ScrnInfoPtr pScrn, int clk,
400				unsigned char n, unsigned char m,
401				unsigned char p)
402{
403	S3OutTiIndReg(pScrn, TIDAC_pll_addr, 0x00, 0x00);
404
405	if (clk != TIDAC_pll_memory_data) {
406		S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00, n);
407		S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00, m);
408		S3OutTiIndReg(pScrn, TIDAC_pll_pixel_data, 0x00, p | 0x08);
409
410		S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00, 0x01);
411		S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00, 0x01);
412		S3OutTiIndReg(pScrn, TIDAC_pll_loop_data, 0x00, p > 0 ? p : 1);
413		S3OutTiIndReg(pScrn, TIDAC_misc_ctrl, 0x00, 0x80 | 0x40 | 0x04);
414
415		S3OutTiIndReg(pScrn, TIDAC_clock_select, 0x00, 0x05);
416	} else {
417		S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00, n);
418		S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00, m);
419		S3OutTiIndReg(pScrn, TIDAC_pll_memory_data, 0x00, p | 0x80);
420	}
421}
422
423
424static void S3TiDACSetClock(ScrnInfoPtr pScrn, long freq, int clk)
425{
426	int m, n, p;
427
428	S3TiDACCalcNMP(freq, &n, &m, &p);
429
430	S3TiDACProgramClock(pScrn, clk, n, m, p);
431}
432
433
434
435void S3TiDAC_Init(ScrnInfoPtr pScrn, DisplayModePtr mode)
436{
437        S3Ptr pS3 = S3PTR(pScrn);
438        vgaHWPtr hwp = VGAHWPTR(pScrn);
439        vgaRegPtr pVga = &hwp->ModeReg;
440        int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
441	unsigned char tmp, tmp1, tmp2;
442
443	S3TiDACSetClock(pScrn, mode->Clock, 2);
444	outb(vgaCRIndex, 0x42);
445	tmp = inb(vgaCRReg) & 0xf0;
446	outb(vgaCRReg, tmp | 0x02);
447	usleep(150000);
448
449	outb(0x3c4, 1);
450	tmp2 = inb(0x3c5);
451	outb(0x3c5, tmp2 | 0x20);	/* blank */
452
453	tmp = pVga->MiscOutReg;
454	pVga->MiscOutReg |= 0xc0;
455	tmp1 = 0x00;
456	if (!(tmp & 0x80))
457		tmp1 |= 0x02;
458      	if (!(tmp & 0x40))
459		tmp1 |= 0x01;
460
461	S3OutTiIndReg(pScrn, TIDAC_general_ctrl, 0x00, tmp1);
462	S3OutTiIndReg(pScrn, 0x0e, 0x00, 0x00);
463
464	/* XXX do 3020 input_clock_sel */
465
466	outb(vgaCRIndex, 0x65);
467	/* XXX 3025 */
468	outb(vgaCRReg, 0x00);
469
470	/* XXX 3025 */
471	outb(vgaCRIndex, 0x40);
472	outb(vgaCRReg, 0x11);
473	outb(vgaCRIndex, 0x55);
474	outb(vgaCRReg, 0x00);
475
476	if (pScrn->bitsPerPixel > 8)
477		S3OutTiIndReg(pScrn, TIDAC_auxiliary_ctrl, 0x00, 0x00);
478	else
479		S3OutTiIndReg(pScrn, TIDAC_auxiliary_ctrl, 0x00, 0x01);
480
481	switch (pScrn->depth) {
482	case 8:
483		S3OutTiIndReg(pScrn, TIDAC_output_clock_select, 0x00,
484			      0x4b);
485		outb(vgaCRIndex, 0x66);
486		tmp = inb(vgaCRReg);
487		if (mode->Clock > 80000)
488			outb(vgaCRReg, (tmp & 0xf8) | 0x02);
489		else
490			outb(vgaCRReg, (tmp & 0xf8) | 0x03);
491		break;
492	case 16:
493		S3OutTiIndReg(pScrn, TIDAC_output_clock_select, 0x00,
494			      0x4a);
495		outb(vgaCRIndex, 0x66);
496		tmp = inb(vgaCRReg);
497		if (mode->Clock > 80000)
498			outb(vgaCRReg, (tmp & 0xf8) | 0x01);
499		else
500			outb(vgaCRReg, (tmp & 0xf8) | 0x02);
501		break;
502	case 24:
503		S3OutTiIndReg(pScrn, TIDAC_output_clock_select, 0x00,
504			      (0x40 | 0x08 | 0x01));
505		outb(vgaCRIndex, 0x66);
506		tmp = inb(vgaCRReg);
507		if (mode->Clock > 80000)
508			outb(vgaCRReg, (tmp & 0xf8) | 0x00);
509		else
510			outb(vgaCRReg, (tmp & 0xf8) | 0x01);
511		break;
512	}
513
514	outb(vgaCRIndex, 0x58);
515	tmp = inb(vgaCRReg);
516	outb(vgaCRReg, (tmp & 0xbf) | 0x40);
517
518	switch(pScrn->depth) {
519	case 8:
520		S3OutTiIndReg(pScrn, TIDAC_true_color_ctrl, 0x00, 0x80);
521		S3OutTiIndReg(pScrn, TIDAC_multiplex_ctrl, 0x00, 0x1c);
522		break;
523	case 15:
524		S3OutTiIndReg(pScrn, TIDAC_true_color_ctrl, 0x00, 0x4c);
525		S3OutTiIndReg(pScrn, TIDAC_multiplex_ctrl, 0x00, 0x04);
526		S3OutTiIndReg(pScrn, TIDAC_key_ctrl, 0x00, 0x01);
527		break;
528	case 16:
529		S3OutTiIndReg(pScrn, TIDAC_true_color_ctrl, 0x00, 0x4d);
530		S3OutTiIndReg(pScrn, TIDAC_multiplex_ctrl, 0x00, 0x04);
531		S3OutTiIndReg(pScrn, TIDAC_key_ctrl, 0x00, 0x01);
532		break;
533	case 24:
534		S3OutTiIndReg(pScrn, TIDAC_true_color_ctrl, 0x00, 0x4e);
535		S3OutTiIndReg(pScrn, TIDAC_multiplex_ctrl, 0x00, 0x04);
536		S3OutTiIndReg(pScrn, TIDAC_key_ctrl, 0x00, 0x01);
537		break;
538	}
539
540	S3OutTiIndReg(pScrn, TIDAC_general_io_ctrl, 0x00, 0x1f);
541	S3OutTiIndReg(pScrn, TIDAC_general_io_data, 0x00, 0x01);
542	S3OutTiIndReg(pScrn, TIDAC_general_io_ctrl, 0x00, 0x00);
543	S3OutTiIndReg(pScrn, TIDAC_misc_ctrl, 0xf0, (0x04 | 0x08));
544
545	outb(vgaCRIndex, 0x6d);
546	if (pS3->s3Bpp == 1)
547		if (mode->Clock > 80000)
548			outb(vgaCRReg, 0x02);
549		else
550			outb(vgaCRReg, 0x03);
551	else if (pS3->s3Bpp == 2)
552		if (mode->Clock > 80000)
553			outb(vgaCRReg, 0x00);
554		else
555			outb(vgaCRReg, 0x01);
556	else
557		outb(vgaCRReg, 0x00);
558
559	S3OutTiIndReg(pScrn, TIDAC_sense_test, 0x00, 0x00);
560
561	if (pS3->s3Bpp > 1)
562	{
563		int j;
564
565		outb(0x3c6, 0xff);
566		outb(0x3c8, 0x00);
567		for(j=0; j<768; j++) {
568			outb(0x3c9, j);
569			outb(0x3c9, j);
570			outb(0x3c9, j);
571		}
572	}
573
574	outb(0x3c4, 1);
575	outb(0x3c5, tmp2);	/* unblank */
576}
577
578
579void S3TiLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies, LOCO *colors,
580		     VisualPtr pVisual)
581{
582	int i;
583
584	outb(0x3c6, 0xff);
585	outb(0x3c8, 0x00);
586
587	for (i=0; i<768; i++) {
588		outb(0x3c9, i);
589		usleep(1000);
590		outb(0x3c9, i);
591		usleep(1000);
592		outb(0x3c9, i);
593		usleep(1000);
594	}
595}
596
597
598
599/* hardware cursor */
600
601static void S3TiSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
602{
603        S3Ptr pS3 = S3PTR(pScrn);
604        int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
605
606        /* unlock sys regs */
607        outb(vgaCRIndex, 0x39);
608        outb(vgaCRReg, 0xa5);
609
610	S3OutTiIndReg(pScrn, TIDAC_cursor_color_0_red, 0x00,
611		      (bg & 0x00FF0000) >> 16);
612	S3OutTiIndReg(pScrn, TIDAC_cursor_color_0_green, 0x00,
613		      (bg & 0x0000FF00) >> 8);
614	S3OutTiIndReg(pScrn, TIDAC_cursor_color_0_blue, 0x00,
615		      (bg & 0x000000FF));
616
617	S3OutTiIndReg(pScrn, TIDAC_cursor_color_1_red, 0x00,
618		      (fg & 0x00FF0000) >> 16);
619	S3OutTiIndReg(pScrn, TIDAC_cursor_color_1_green, 0x00,
620		      (fg & 0x0000FF00) >> 8);
621	S3OutTiIndReg(pScrn, TIDAC_cursor_color_1_blue, 0x00,
622		      (fg & 0x000000FF));
623
624}
625
626
627static void S3TiSetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
628{
629        S3Ptr pS3 = S3PTR(pScrn);
630        int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
631
632        /* unlock sys regs */
633        outb(vgaCRIndex, 0x39);
634        outb(vgaCRReg, 0xa5);
635
636	S3OutTiIndReg(pScrn, TIDAC_cursor_x_low, 0x00, x & 0xff);
637	S3OutTiIndReg(pScrn, TIDAC_cursor_x_high, 0x00, (x >> 8) & 0x0f);
638	S3OutTiIndReg(pScrn, TIDAC_cursor_y_low, 0x00, y & 0xff);
639	S3OutTiIndReg(pScrn, TIDAC_cursor_y_high, 0x00, (y >> 8) & 0x0f);
640}
641
642
643static void S3TiHideCursor(ScrnInfoPtr pScrn)
644{
645        S3Ptr pS3 = S3PTR(pScrn);
646        int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
647
648        /* unlock sys regs */
649        outb(vgaCRIndex, 0x39);
650        outb(vgaCRReg, 0xa5);
651
652	S3OutTiIndReg(pScrn, TIDAC_ind_curs_ctrl, (unsigned char)
653		      ~(0x40 | 0x10), 0x00);
654}
655
656
657static void S3TiShowCursor(ScrnInfoPtr pScrn)
658{
659        S3Ptr pS3 = S3PTR(pScrn);
660        int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
661        unsigned char tmp;
662
663        /* unlock sys regs */
664        outb(vgaCRIndex, 0x39);
665        outb(vgaCRReg, 0xa5);
666
667	outb(vgaCRIndex, 0x55);
668	tmp = inb(vgaCRReg) & 0xdf;
669	outb(vgaCRReg, tmp | 0x20);
670
671	outb(vgaCRIndex, 0x45);
672	tmp = inb(vgaCRReg) & 0xdf;
673	outb(vgaCRReg, tmp | 0x20);
674
675	S3OutTiIndReg(pScrn, TIDAC_ind_curs_ctrl, (unsigned char)
676		      ~(0x40 | 0x10), (0x40 | 0x10));
677}
678
679
680static void S3TiLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *image)
681{
682        S3Ptr pS3 = S3PTR(pScrn);
683        int vgaCRIndex = pS3->vgaCRIndex, vgaCRReg = pS3->vgaCRReg;
684        unsigned char tmp, tmp1;
685        register int i;
686#if 0
687	register unsigned char *mask = image + 1;
688#endif
689
690        /* unlock sys regs */
691        outb(vgaCRIndex, 0x39);
692        outb(vgaCRReg, 0xa5);
693
694	outb(vgaCRIndex, 0x55);
695	tmp = inb(vgaCRReg) & 0xfc;
696	outb(vgaCRReg, tmp | 0x01);
697	tmp1 = inb(TI_INDEX_REG);
698
699	outb(TI_INDEX_REG, TIDAC_cursor_ram_addr_low);
700	outb(TI_DATA_REG, 0x00);
701	outb(TI_INDEX_REG, TIDAC_cursor_ram_addr_high);
702	outb(TI_DATA_REG, 0x00);
703	outb(TI_INDEX_REG, TIDAC_cursor_ram_data);
704
705#if 0
706	for (i=0; i<512; i++, mask+=2)
707		outb(TI_DATA_REG, *mask);
708	for (i=0; i<512; i++, image+=2)
709		outb(TI_DATA_REG, *image);
710#else
711	for (i=0; i<1024; i++) {
712		outb(TI_DATA_REG, *image);
713		image++;
714	}
715#endif
716
717	outb(TI_INDEX_REG, tmp1);
718
719	outb(vgaCRIndex, 0x55);
720	outb(vgaCRReg, tmp);
721}
722
723
724
725static Bool S3TiUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
726{
727	ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
728	S3Ptr pS3 = S3PTR(pScrn);
729	return (pS3->hwCursor);
730}
731
732
733
734Bool S3Ti_CursorInit(ScreenPtr pScreen)
735{
736        ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
737        S3Ptr pS3 = S3PTR(pScrn);
738        xf86CursorInfoPtr pCurs;
739
740        if (!(pCurs = pS3->pCurs = xf86CreateCursorInfoRec()))
741                return FALSE;
742
743        pCurs->MaxWidth = 64;
744        pCurs->MaxHeight = 64;
745        pCurs->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
746		       HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
747		       HARDWARE_CURSOR_NIBBLE_SWAPPED |
748		       HARDWARE_CURSOR_BIT_ORDER_MSBFIRST;
749
750        pCurs->SetCursorColors = S3TiSetCursorColors;
751        pCurs->SetCursorPosition = S3TiSetCursorPosition;
752        pCurs->LoadCursorImage = S3TiLoadCursorImage;
753        pCurs->HideCursor = S3TiHideCursor;
754        pCurs->ShowCursor = S3TiShowCursor;
755        pCurs->UseHWCursor = S3TiUseHWCursor;
756
757        return xf86InitCursor(pScreen, pCurs);
758}
759