xref: /plan9/sys/src/cmd/aux/vga/tvp3020.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 
5 #include "pci.h"
6 #include "vga.h"
7 
8 /*
9  * Tvp302[056] Viewpoint Video Interface Palette.
10  * Assumes hooked up to an S3 86C928 or S3 Vision964.
11  */
12 enum {
13 	Index		= 0x06,		/* Index register */
14 	Data		= 0x07,		/* Data register */
15 
16 	Id		= 0x3F,		/* ID Register */
17 	Tvp3020		= 0x20,
18 	Tvp3025		= 0x25,
19 	Tvp3026		= 0x26,
20 };
21 
22 /*
23  * The following two arrays give read (bit 0) and write (bit 1)
24  * permissions on the direct and index registers. Bits 4 and 5
25  * are for the Tvp3025. The Tvp3020 has only 8 direct registers.
26  */
27 static uchar directreg[32] = {
28 	0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x33, 0x33,
29 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30 	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
31 	0x33, 0x33, 0x11, 0x33, 0x33, 0x33, 0x33, 0x33,
32 };
33 
34 static uchar indexreg[64] = {
35 	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00,
36 	0x02, 0x02, 0x33, 0x00, 0x00, 0x00, 0x30, 0x30,
37 	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
38 	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x30, 0x00,
39 	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
40 	0x33, 0x33, 0x33, 0x33, 0x30, 0x30, 0x30, 0x30,
41 	0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
42 	0x33, 0x30, 0x33, 0x11, 0x11, 0x11, 0x22, 0x11,
43 };
44 
45 /*
46  * Check the index register access is valid.
47  * Return the number of direct registers.
48  */
49 static uchar
checkindex(uchar index,uchar access)50 checkindex(uchar index, uchar access)
51 {
52 	uchar crt55;
53 	static uchar id;
54 
55 	if(id == 0){
56 		crt55 = vgaxi(Crtx, 0x55) & 0xFC;
57 		vgaxo(Crtx, 0x55, crt55|((Index>>2) & 0x03));
58 		vgao(dacxreg[Index & 0x03], Id);
59 
60 		id = vgai(dacxreg[Data & 0x03]);
61 		vgaxo(Crtx, 0x55, crt55);
62 	}
63 
64 	if(index == 0xFF)
65 		return id;
66 
67 	access &= 0x03;
68 	switch(id){
69 
70 	case Tvp3020:
71 		break;
72 
73 	case Tvp3025:
74 	case Tvp3026:
75 		access = access<<4;
76 		break;
77 
78 	default:
79 		Bprint(&stdout, "%s: unknown chip id - 0x%2.2X\n", tvp3020.name, id);
80 		break;
81 	}
82 
83 	if(index > sizeof(indexreg) || (indexreg[index] & access) == 0)
84 		error("%s: bad register index - 0x%2.2X\n", tvp3020.name, index);
85 
86 	return id;
87 }
88 
89 static uchar
tvp3020io(uchar reg,uchar data)90 tvp3020io(uchar reg, uchar data)
91 {
92 	uchar crt55;
93 
94 	crt55 = vgaxi(Crtx, 0x55) & 0xFC;
95 	vgaxo(Crtx, 0x55, crt55|((reg>>2) & 0x03));
96 	vgao(dacxreg[reg & 0x03], data);
97 
98 	return crt55;
99 }
100 
101 uchar
tvp3020i(uchar reg)102 tvp3020i(uchar reg)
103 {
104 	uchar crt55, r;
105 
106 	crt55 = vgaxi(Crtx, 0x55) & 0xFC;
107 	vgaxo(Crtx, 0x55, crt55|((reg>>2) & 0x03));
108 	r = vgai(dacxreg[reg & 0x03]);
109 	vgaxo(Crtx, 0x55, crt55);
110 
111 	return r;
112 }
113 
114 uchar
tvp3020xi(uchar index)115 tvp3020xi(uchar index)
116 {
117 	uchar crt55, r;
118 
119 	checkindex(index, 0x01);
120 
121 	crt55 = tvp3020io(Index, index);
122 	r = vgai(dacxreg[Data & 0x03]);
123 	vgaxo(Crtx, 0x55, crt55);
124 
125 	return r;
126 }
127 
128 void
tvp3020o(uchar reg,uchar data)129 tvp3020o(uchar reg, uchar data)
130 {
131 	uchar crt55;
132 
133 	crt55 = tvp3020io(reg, data);
134 	vgaxo(Crtx, 0x55, crt55);
135 }
136 
137 void
tvp3020xo(uchar index,uchar data)138 tvp3020xo(uchar index, uchar data)
139 {
140 	uchar crt55;
141 
142 	checkindex(index, 0x02);
143 
144 	crt55 = tvp3020io(Index, index);
145 	vgao(dacxreg[Data & 0x03], data);
146 	vgaxo(Crtx, 0x55, crt55);
147 }
148 
149 static void
options(Vga *,Ctlr * ctlr)150 options(Vga*, Ctlr* ctlr)
151 {
152 	ctlr->flag |= Hclk2|Hextsid|Hpvram|Henhanced|Foptions;
153 }
154 
155 static void
init(Vga * vga,Ctlr * ctlr)156 init(Vga* vga, Ctlr* ctlr)
157 {
158 	ulong grade;
159 	char *p;
160 
161 	/*
162 	 * Work out the part speed-grade from name. Name can have,
163 	 * e.g. '-135' on the end  for 135MHz part.
164 	 */
165 	grade = 110000000;
166 	if(p = strrchr(ctlr->name, '-'))
167 		grade = strtoul(p+1, 0, 0) * 1000000;
168 
169 	/*
170 	 * If we don't already have a desired pclk,
171 	 * take it from the mode.
172 	 * Check it's within range.
173 	 */
174 	if(vga->f[0] == 0)
175 		vga->f[0] = vga->mode->frequency;
176 	if(vga->f[0] > grade)
177 		error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]);
178 
179 	/*
180 	 * Determine whether to use clock-doubler or not.
181 	 */
182 	if(vga->f[0] > 85000000){
183 		vga->f[0] /= 2;
184 		resyncinit(vga, ctlr, Uclk2, 0);
185 	}
186 
187 	ctlr->flag |= Finit;
188 }
189 
190 static void
load(Vga * vga,Ctlr * ctlr)191 load(Vga* vga, Ctlr* ctlr)
192 {
193 	uchar x;
194 
195 	/*
196 	 * Input Clock Selection:
197 	 *	VGA		CLK0
198 	 * 	enhanced	CLK1
199 	 * doubled if necessary.
200 	 */
201 	x = 0x00;
202 	if(ctlr->flag & Uenhanced)
203 		x |= 0x01;
204 	if(ctlr->flag & Uclk2)
205 		x |= 0x10;
206 	tvp3020xo(0x1A, x);
207 
208 	/*
209 	 * Output Clock Selection:
210 	 *	VGA		default VGA
211 	 *	enhanced	RCLK=SCLK=/8, VCLK/4
212 	 */
213 	x = 0x3E;
214 	if(ctlr->flag & Uenhanced)
215 		x = 0x53;
216 	tvp3020xo(0x1B, x);
217 
218 	/*
219 	 * Auxiliary Control:
220 	 *	default settings - self-clocked, palette graphics, no zoom
221 	 * Colour Key Control:
222 	 *	default settings - pointing to palette graphics
223 	 * Mux Control Register 1:
224 	 *	pseudo colour
225 	 */
226 	tvp3020xo(0x29, 0x09);
227 	tvp3020xo(0x38, 0x10);
228 	tvp3020xo(0x18, 0x80);
229 
230 	/*
231 	 * Mux Control Register 2:
232 	 *	VGA		default VGA
233 	 *	enhanced	8-bpp, 8:1 mux, 64-bit pixel-bus width
234 	 */
235 	x = 0x98;
236 	if(ctlr->flag & Uenhanced){
237 		if(vga->mode->z == 8)
238 			x = 0x1C;
239 		else if(vga->mode->z == 1)
240 			x = 0x04;
241 	}
242 	tvp3020xo(0x19, x);
243 
244 	/*
245 	 * General Control:
246 	 *	output sync polarity
247 	 * It's important to set this properly and to turn off the
248 	 * VGA controller H and V syncs. Can't be set in VGA mode.
249 	 */
250 	x = 0x00;
251 	if((vga->misc & 0x40) == 0)
252 		x |= 0x01;
253 	if((vga->misc & 0x80) == 0)
254 		x |= 0x02;
255 	tvp3020xo(0x1D, x);
256 	vga->misc |= 0xC0;
257 	vgao(MiscW, vga->misc);
258 
259 	/*
260 	 * Select the DAC via the General Purpose I/O
261 	 * Register and Pins.
262 	 * Guesswork by looking at register dumps.
263 	 */
264 	tvp3020xo(0x2A, 0x1F);
265 	if(ctlr->flag & Uenhanced)
266 		x = 0x1D;
267 	else
268 		x = 0x1C;
269 	tvp3020xo(0x2B, x);
270 
271 	ctlr->flag |= Fload;
272 }
273 
274 static void
dump(Vga *,Ctlr * ctlr)275 dump(Vga*, Ctlr* ctlr)
276 {
277 	uchar access;
278 	int i;
279 
280 	access = 0x01;
281 	if(checkindex(0x00, 0x01) != Tvp3020)
282 		access <<= 4;
283 
284 	printitem(ctlr->name, "direct");
285 	for(i = 0; i < 8; i++){
286 		if(directreg[i] & access)
287 			printreg(tvp3020i(i));
288 		else
289 			printreg(0xFF);
290 	}
291 
292 	printitem(ctlr->name, "index");
293 	for(i = 0; i < sizeof(indexreg); i++){
294 		if(indexreg[i] & access)
295 			printreg(tvp3020xi(i));
296 		else
297 			printreg(0xFF);
298 	}
299 }
300 
301 Ctlr tvp3020 = {
302 	"tvp3020",			/* name */
303 	0,				/* snarf */
304 	options,			/* options */
305 	init,				/* init */
306 	load,				/* load */
307 	dump,				/* dump */
308 };
309