xref: /plan9/sys/src/cmd/aux/vga/tvp3020.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1219b2ee8SDavid du Colombier #include <u.h>
2219b2ee8SDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
4219b2ee8SDavid du Colombier 
5*9a747e4fSDavid du Colombier #include "pci.h"
6219b2ee8SDavid du Colombier #include "vga.h"
7219b2ee8SDavid du Colombier 
8219b2ee8SDavid du Colombier /*
97dd7cddfSDavid du Colombier  * Tvp302[056] Viewpoint Video Interface Palette.
10219b2ee8SDavid du Colombier  * Assumes hooked up to an S3 86C928 or S3 Vision964.
11219b2ee8SDavid du Colombier  */
12219b2ee8SDavid du Colombier enum {
13219b2ee8SDavid du Colombier 	Index		= 0x06,		/* Index register */
14219b2ee8SDavid du Colombier 	Data		= 0x07,		/* Data register */
15219b2ee8SDavid du Colombier 
16219b2ee8SDavid du Colombier 	Id		= 0x3F,		/* ID Register */
17219b2ee8SDavid du Colombier 	Tvp3020		= 0x20,
18219b2ee8SDavid du Colombier 	Tvp3025		= 0x25,
197dd7cddfSDavid du Colombier 	Tvp3026		= 0x26,
20219b2ee8SDavid du Colombier };
21219b2ee8SDavid du Colombier 
22219b2ee8SDavid du Colombier /*
23219b2ee8SDavid du Colombier  * The following two arrays give read (bit 0) and write (bit 1)
24219b2ee8SDavid du Colombier  * permissions on the direct and index registers. Bits 4 and 5
25219b2ee8SDavid du Colombier  * are for the Tvp3025. The Tvp3020 has only 8 direct registers.
26219b2ee8SDavid du Colombier  */
27219b2ee8SDavid du Colombier static uchar directreg[32] = {
28219b2ee8SDavid du Colombier 	0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x33, 0x33,
29219b2ee8SDavid du Colombier 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30219b2ee8SDavid du Colombier 	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
31219b2ee8SDavid du Colombier 	0x33, 0x33, 0x11, 0x33, 0x33, 0x33, 0x33, 0x33,
32219b2ee8SDavid du Colombier };
33219b2ee8SDavid du Colombier 
34219b2ee8SDavid du Colombier static uchar indexreg[64] = {
35219b2ee8SDavid du Colombier 	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00,
36219b2ee8SDavid du Colombier 	0x02, 0x02, 0x33, 0x00, 0x00, 0x00, 0x30, 0x30,
37219b2ee8SDavid du Colombier 	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
38219b2ee8SDavid du Colombier 	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x30, 0x00,
39219b2ee8SDavid du Colombier 	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
40219b2ee8SDavid du Colombier 	0x33, 0x33, 0x33, 0x33, 0x30, 0x30, 0x30, 0x30,
41219b2ee8SDavid du Colombier 	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
42219b2ee8SDavid du Colombier 	0x33, 0x30, 0x33, 0x11, 0x11, 0x11, 0x22, 0x11,
43219b2ee8SDavid du Colombier };
44219b2ee8SDavid du Colombier 
45219b2ee8SDavid du Colombier /*
46219b2ee8SDavid du Colombier  * Check the index register access is valid.
47219b2ee8SDavid du Colombier  * Return the number of direct registers.
48219b2ee8SDavid du Colombier  */
49219b2ee8SDavid du Colombier static uchar
checkindex(uchar index,uchar access)50219b2ee8SDavid du Colombier checkindex(uchar index, uchar access)
51219b2ee8SDavid du Colombier {
52219b2ee8SDavid du Colombier 	uchar crt55;
53219b2ee8SDavid du Colombier 	static uchar id;
54219b2ee8SDavid du Colombier 
55219b2ee8SDavid du Colombier 	if(id == 0){
56219b2ee8SDavid du Colombier 		crt55 = vgaxi(Crtx, 0x55) & 0xFC;
57219b2ee8SDavid du Colombier 		vgaxo(Crtx, 0x55, crt55|((Index>>2) & 0x03));
58219b2ee8SDavid du Colombier 		vgao(dacxreg[Index & 0x03], Id);
59219b2ee8SDavid du Colombier 
60219b2ee8SDavid du Colombier 		id = vgai(dacxreg[Data & 0x03]);
61219b2ee8SDavid du Colombier 		vgaxo(Crtx, 0x55, crt55);
62219b2ee8SDavid du Colombier 	}
63219b2ee8SDavid du Colombier 
64219b2ee8SDavid du Colombier 	if(index == 0xFF)
65219b2ee8SDavid du Colombier 		return id;
66219b2ee8SDavid du Colombier 
67219b2ee8SDavid du Colombier 	access &= 0x03;
68219b2ee8SDavid du Colombier 	switch(id){
69219b2ee8SDavid du Colombier 
70219b2ee8SDavid du Colombier 	case Tvp3020:
71219b2ee8SDavid du Colombier 		break;
72219b2ee8SDavid du Colombier 
73219b2ee8SDavid du Colombier 	case Tvp3025:
747dd7cddfSDavid du Colombier 	case Tvp3026:
75219b2ee8SDavid du Colombier 		access = access<<4;
76219b2ee8SDavid du Colombier 		break;
77219b2ee8SDavid du Colombier 
78219b2ee8SDavid du Colombier 	default:
797dd7cddfSDavid du Colombier 		Bprint(&stdout, "%s: unknown chip id - 0x%2.2X\n", tvp3020.name, id);
80219b2ee8SDavid du Colombier 		break;
81219b2ee8SDavid du Colombier 	}
82219b2ee8SDavid du Colombier 
83219b2ee8SDavid du Colombier 	if(index > sizeof(indexreg) || (indexreg[index] & access) == 0)
847dd7cddfSDavid du Colombier 		error("%s: bad register index - 0x%2.2X\n", tvp3020.name, index);
85219b2ee8SDavid du Colombier 
86219b2ee8SDavid du Colombier 	return id;
87219b2ee8SDavid du Colombier }
88219b2ee8SDavid du Colombier 
89219b2ee8SDavid du Colombier static uchar
tvp3020io(uchar reg,uchar data)90219b2ee8SDavid du Colombier tvp3020io(uchar reg, uchar data)
91219b2ee8SDavid du Colombier {
92219b2ee8SDavid du Colombier 	uchar crt55;
93219b2ee8SDavid du Colombier 
94219b2ee8SDavid du Colombier 	crt55 = vgaxi(Crtx, 0x55) & 0xFC;
95219b2ee8SDavid du Colombier 	vgaxo(Crtx, 0x55, crt55|((reg>>2) & 0x03));
96219b2ee8SDavid du Colombier 	vgao(dacxreg[reg & 0x03], data);
97219b2ee8SDavid du Colombier 
98219b2ee8SDavid du Colombier 	return crt55;
99219b2ee8SDavid du Colombier }
100219b2ee8SDavid du Colombier 
101219b2ee8SDavid du Colombier uchar
tvp3020i(uchar reg)102219b2ee8SDavid du Colombier tvp3020i(uchar reg)
103219b2ee8SDavid du Colombier {
104219b2ee8SDavid du Colombier 	uchar crt55, r;
105219b2ee8SDavid du Colombier 
106219b2ee8SDavid du Colombier 	crt55 = vgaxi(Crtx, 0x55) & 0xFC;
107219b2ee8SDavid du Colombier 	vgaxo(Crtx, 0x55, crt55|((reg>>2) & 0x03));
108219b2ee8SDavid du Colombier 	r = vgai(dacxreg[reg & 0x03]);
109219b2ee8SDavid du Colombier 	vgaxo(Crtx, 0x55, crt55);
110219b2ee8SDavid du Colombier 
111219b2ee8SDavid du Colombier 	return r;
112219b2ee8SDavid du Colombier }
113219b2ee8SDavid du Colombier 
114219b2ee8SDavid du Colombier uchar
tvp3020xi(uchar index)115219b2ee8SDavid du Colombier tvp3020xi(uchar index)
116219b2ee8SDavid du Colombier {
117219b2ee8SDavid du Colombier 	uchar crt55, r;
118219b2ee8SDavid du Colombier 
119219b2ee8SDavid du Colombier 	checkindex(index, 0x01);
120219b2ee8SDavid du Colombier 
121219b2ee8SDavid du Colombier 	crt55 = tvp3020io(Index, index);
122219b2ee8SDavid du Colombier 	r = vgai(dacxreg[Data & 0x03]);
123219b2ee8SDavid du Colombier 	vgaxo(Crtx, 0x55, crt55);
124219b2ee8SDavid du Colombier 
125219b2ee8SDavid du Colombier 	return r;
126219b2ee8SDavid du Colombier }
127219b2ee8SDavid du Colombier 
128219b2ee8SDavid du Colombier void
tvp3020o(uchar reg,uchar data)129219b2ee8SDavid du Colombier tvp3020o(uchar reg, uchar data)
130219b2ee8SDavid du Colombier {
131219b2ee8SDavid du Colombier 	uchar crt55;
132219b2ee8SDavid du Colombier 
133219b2ee8SDavid du Colombier 	crt55 = tvp3020io(reg, data);
134219b2ee8SDavid du Colombier 	vgaxo(Crtx, 0x55, crt55);
135219b2ee8SDavid du Colombier }
136219b2ee8SDavid du Colombier 
137219b2ee8SDavid du Colombier void
tvp3020xo(uchar index,uchar data)138219b2ee8SDavid du Colombier tvp3020xo(uchar index, uchar data)
139219b2ee8SDavid du Colombier {
140219b2ee8SDavid du Colombier 	uchar crt55;
141219b2ee8SDavid du Colombier 
142219b2ee8SDavid du Colombier 	checkindex(index, 0x02);
143219b2ee8SDavid du Colombier 
144219b2ee8SDavid du Colombier 	crt55 = tvp3020io(Index, index);
145219b2ee8SDavid du Colombier 	vgao(dacxreg[Data & 0x03], data);
146219b2ee8SDavid du Colombier 	vgaxo(Crtx, 0x55, crt55);
147219b2ee8SDavid du Colombier }
148219b2ee8SDavid du Colombier 
149219b2ee8SDavid du Colombier static void
options(Vga *,Ctlr * ctlr)1507dd7cddfSDavid du Colombier options(Vga*, Ctlr* ctlr)
151219b2ee8SDavid du Colombier {
152219b2ee8SDavid du Colombier 	ctlr->flag |= Hclk2|Hextsid|Hpvram|Henhanced|Foptions;
153219b2ee8SDavid du Colombier }
154219b2ee8SDavid du Colombier 
155219b2ee8SDavid du Colombier static void
init(Vga * vga,Ctlr * ctlr)156219b2ee8SDavid du Colombier init(Vga* vga, Ctlr* ctlr)
157219b2ee8SDavid du Colombier {
158219b2ee8SDavid du Colombier 	ulong grade;
159219b2ee8SDavid du Colombier 	char *p;
160219b2ee8SDavid du Colombier 
161219b2ee8SDavid du Colombier 	/*
162219b2ee8SDavid du Colombier 	 * Work out the part speed-grade from name. Name can have,
163219b2ee8SDavid du Colombier 	 * e.g. '-135' on the end  for 135MHz part.
164219b2ee8SDavid du Colombier 	 */
165219b2ee8SDavid du Colombier 	grade = 110000000;
166219b2ee8SDavid du Colombier 	if(p = strrchr(ctlr->name, '-'))
167219b2ee8SDavid du Colombier 		grade = strtoul(p+1, 0, 0) * 1000000;
168219b2ee8SDavid du Colombier 
169219b2ee8SDavid du Colombier 	/*
170219b2ee8SDavid du Colombier 	 * If we don't already have a desired pclk,
171219b2ee8SDavid du Colombier 	 * take it from the mode.
172219b2ee8SDavid du Colombier 	 * Check it's within range.
173219b2ee8SDavid du Colombier 	 */
1747dd7cddfSDavid du Colombier 	if(vga->f[0] == 0)
1757dd7cddfSDavid du Colombier 		vga->f[0] = vga->mode->frequency;
1767dd7cddfSDavid du Colombier 	if(vga->f[0] > grade)
1777dd7cddfSDavid du Colombier 		error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]);
178219b2ee8SDavid du Colombier 
179219b2ee8SDavid du Colombier 	/*
180219b2ee8SDavid du Colombier 	 * Determine whether to use clock-doubler or not.
181219b2ee8SDavid du Colombier 	 */
1827dd7cddfSDavid du Colombier 	if(vga->f[0] > 85000000){
1837dd7cddfSDavid du Colombier 		vga->f[0] /= 2;
184219b2ee8SDavid du Colombier 		resyncinit(vga, ctlr, Uclk2, 0);
185219b2ee8SDavid du Colombier 	}
186219b2ee8SDavid du Colombier 
187219b2ee8SDavid du Colombier 	ctlr->flag |= Finit;
188219b2ee8SDavid du Colombier }
189219b2ee8SDavid du Colombier 
190219b2ee8SDavid du Colombier static void
load(Vga * vga,Ctlr * ctlr)191219b2ee8SDavid du Colombier load(Vga* vga, Ctlr* ctlr)
192219b2ee8SDavid du Colombier {
193219b2ee8SDavid du Colombier 	uchar x;
194219b2ee8SDavid du Colombier 
195219b2ee8SDavid du Colombier 	/*
196219b2ee8SDavid du Colombier 	 * Input Clock Selection:
197219b2ee8SDavid du Colombier 	 *	VGA		CLK0
198219b2ee8SDavid du Colombier 	 * 	enhanced	CLK1
199219b2ee8SDavid du Colombier 	 * doubled if necessary.
200219b2ee8SDavid du Colombier 	 */
201219b2ee8SDavid du Colombier 	x = 0x00;
202219b2ee8SDavid du Colombier 	if(ctlr->flag & Uenhanced)
203219b2ee8SDavid du Colombier 		x |= 0x01;
204219b2ee8SDavid du Colombier 	if(ctlr->flag & Uclk2)
205219b2ee8SDavid du Colombier 		x |= 0x10;
206219b2ee8SDavid du Colombier 	tvp3020xo(0x1A, x);
207219b2ee8SDavid du Colombier 
208219b2ee8SDavid du Colombier 	/*
209219b2ee8SDavid du Colombier 	 * Output Clock Selection:
210219b2ee8SDavid du Colombier 	 *	VGA		default VGA
211219b2ee8SDavid du Colombier 	 *	enhanced	RCLK=SCLK=/8, VCLK/4
212219b2ee8SDavid du Colombier 	 */
213219b2ee8SDavid du Colombier 	x = 0x3E;
214219b2ee8SDavid du Colombier 	if(ctlr->flag & Uenhanced)
215219b2ee8SDavid du Colombier 		x = 0x53;
216219b2ee8SDavid du Colombier 	tvp3020xo(0x1B, x);
217219b2ee8SDavid du Colombier 
218219b2ee8SDavid du Colombier 	/*
219219b2ee8SDavid du Colombier 	 * Auxiliary Control:
220219b2ee8SDavid du Colombier 	 *	default settings - self-clocked, palette graphics, no zoom
221219b2ee8SDavid du Colombier 	 * Colour Key Control:
222219b2ee8SDavid du Colombier 	 *	default settings - pointing to palette graphics
223219b2ee8SDavid du Colombier 	 * Mux Control Register 1:
224219b2ee8SDavid du Colombier 	 *	pseudo colour
225219b2ee8SDavid du Colombier 	 */
226219b2ee8SDavid du Colombier 	tvp3020xo(0x29, 0x09);
227219b2ee8SDavid du Colombier 	tvp3020xo(0x38, 0x10);
228219b2ee8SDavid du Colombier 	tvp3020xo(0x18, 0x80);
229219b2ee8SDavid du Colombier 
230219b2ee8SDavid du Colombier 	/*
231219b2ee8SDavid du Colombier 	 * Mux Control Register 2:
232219b2ee8SDavid du Colombier 	 *	VGA		default VGA
233219b2ee8SDavid du Colombier 	 *	enhanced	8-bpp, 8:1 mux, 64-bit pixel-bus width
234219b2ee8SDavid du Colombier 	 */
235219b2ee8SDavid du Colombier 	x = 0x98;
236219b2ee8SDavid du Colombier 	if(ctlr->flag & Uenhanced){
237219b2ee8SDavid du Colombier 		if(vga->mode->z == 8)
238219b2ee8SDavid du Colombier 			x = 0x1C;
239219b2ee8SDavid du Colombier 		else if(vga->mode->z == 1)
240219b2ee8SDavid du Colombier 			x = 0x04;
241219b2ee8SDavid du Colombier 	}
242219b2ee8SDavid du Colombier 	tvp3020xo(0x19, x);
243219b2ee8SDavid du Colombier 
244219b2ee8SDavid du Colombier 	/*
245219b2ee8SDavid du Colombier 	 * General Control:
246219b2ee8SDavid du Colombier 	 *	output sync polarity
247219b2ee8SDavid du Colombier 	 * It's important to set this properly and to turn off the
248219b2ee8SDavid du Colombier 	 * VGA controller H and V syncs. Can't be set in VGA mode.
249219b2ee8SDavid du Colombier 	 */
250219b2ee8SDavid du Colombier 	x = 0x00;
251219b2ee8SDavid du Colombier 	if((vga->misc & 0x40) == 0)
252219b2ee8SDavid du Colombier 		x |= 0x01;
253219b2ee8SDavid du Colombier 	if((vga->misc & 0x80) == 0)
254219b2ee8SDavid du Colombier 		x |= 0x02;
255219b2ee8SDavid du Colombier 	tvp3020xo(0x1D, x);
256219b2ee8SDavid du Colombier 	vga->misc |= 0xC0;
257219b2ee8SDavid du Colombier 	vgao(MiscW, vga->misc);
258219b2ee8SDavid du Colombier 
259219b2ee8SDavid du Colombier 	/*
260219b2ee8SDavid du Colombier 	 * Select the DAC via the General Purpose I/O
261219b2ee8SDavid du Colombier 	 * Register and Pins.
262219b2ee8SDavid du Colombier 	 * Guesswork by looking at register dumps.
263219b2ee8SDavid du Colombier 	 */
264219b2ee8SDavid du Colombier 	tvp3020xo(0x2A, 0x1F);
265219b2ee8SDavid du Colombier 	if(ctlr->flag & Uenhanced)
266219b2ee8SDavid du Colombier 		x = 0x1D;
267219b2ee8SDavid du Colombier 	else
268219b2ee8SDavid du Colombier 		x = 0x1C;
269219b2ee8SDavid du Colombier 	tvp3020xo(0x2B, x);
270219b2ee8SDavid du Colombier 
271219b2ee8SDavid du Colombier 	ctlr->flag |= Fload;
272219b2ee8SDavid du Colombier }
273219b2ee8SDavid du Colombier 
274219b2ee8SDavid du Colombier static void
dump(Vga *,Ctlr * ctlr)2757dd7cddfSDavid du Colombier dump(Vga*, Ctlr* ctlr)
276219b2ee8SDavid du Colombier {
277219b2ee8SDavid du Colombier 	uchar access;
278219b2ee8SDavid du Colombier 	int i;
279219b2ee8SDavid du Colombier 
280219b2ee8SDavid du Colombier 	access = 0x01;
2817dd7cddfSDavid du Colombier 	if(checkindex(0x00, 0x01) != Tvp3020)
282219b2ee8SDavid du Colombier 		access <<= 4;
283219b2ee8SDavid du Colombier 
284219b2ee8SDavid du Colombier 	printitem(ctlr->name, "direct");
285219b2ee8SDavid du Colombier 	for(i = 0; i < 8; i++){
286219b2ee8SDavid du Colombier 		if(directreg[i] & access)
287219b2ee8SDavid du Colombier 			printreg(tvp3020i(i));
288219b2ee8SDavid du Colombier 		else
289219b2ee8SDavid du Colombier 			printreg(0xFF);
290219b2ee8SDavid du Colombier 	}
291219b2ee8SDavid du Colombier 
292219b2ee8SDavid du Colombier 	printitem(ctlr->name, "index");
293219b2ee8SDavid du Colombier 	for(i = 0; i < sizeof(indexreg); i++){
294219b2ee8SDavid du Colombier 		if(indexreg[i] & access)
295219b2ee8SDavid du Colombier 			printreg(tvp3020xi(i));
296219b2ee8SDavid du Colombier 		else
297219b2ee8SDavid du Colombier 			printreg(0xFF);
298219b2ee8SDavid du Colombier 	}
299219b2ee8SDavid du Colombier }
300219b2ee8SDavid du Colombier 
301219b2ee8SDavid du Colombier Ctlr tvp3020 = {
302219b2ee8SDavid du Colombier 	"tvp3020",			/* name */
303219b2ee8SDavid du Colombier 	0,				/* snarf */
304219b2ee8SDavid du Colombier 	options,			/* options */
305219b2ee8SDavid du Colombier 	init,				/* init */
306219b2ee8SDavid du Colombier 	load,				/* load */
307219b2ee8SDavid du Colombier 	dump,				/* dump */
308219b2ee8SDavid du Colombier };
309