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