xref: /plan9/sys/src/cmd/aux/vga/trio64.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  * S3 Trio64.
10  */
11 static void
snarf(Vga * vga,Ctlr * ctlr)12 snarf(Vga* vga, Ctlr* ctlr)
13 {
14 	int i;
15 
16 	/*
17 	 * The Trio has some extra sequencer registers which
18 	 * need to be unlocked for access.
19 	 */
20 	vgaxo(Seqx, 0x08, 0x06);
21 	for(i = 0x08; i < 0x19; i++)
22 		vga->sequencer[i] = vgaxi(Seqx, i);
23 	vga->crt[0x2D] = vgaxi(Crtx, 0x2D);
24 	vga->crt[0x2E] = vgaxi(Crtx, 0x2E);
25 	vga->crt[0x2F] = vgaxi(Crtx, 0x2F);
26 
27 	s3generic.snarf(vga, ctlr);
28 	ctlr->flag |= Fsnarf;
29 }
30 
31 static void
options(Vga *,Ctlr * ctlr)32 options(Vga*, Ctlr* ctlr)
33 {
34 	ctlr->flag |= Hlinear|Hpclk2x8|Henhanced|Foptions;
35 }
36 
37 void
trio64clock(Vga * vga,Ctlr * ctlr)38 trio64clock(Vga* vga, Ctlr* ctlr)
39 {
40 	int d;
41 	ulong f, fmax, fmin, n, m, r;
42 	double trouble;
43 
44 	/*
45 	 * The max value of R, M, N, and the speed rating of the part vary
46 	 * between parts and are passed to this routine in r[1] and f[1].
47 	 *			R	    F
48 	 *	Trio64		3	135000000
49 	 *	ViRGE		3	135000000
50 	 *	ViRGE/[DG]X	4	170000000
51 	 *	ViRGE/GX2	4	170000000
52 	 *	ViRGE/VX	4	220000000
53 	 */
54 
55 	/*
56 	 * The PLL frequency is defined by the following equation:
57 	 *		   (M+2)
58 	 *	Fout = ------------- x Fref
59 	 *		(N+2) x 2**R
60 	 * where M, N and R have the following contraints:
61 	 * 1)		   (M+2) x Fref
62 	 *    vga->f[1] <= ------------ <= vga->f[1]*2
63 	 *		       (N+2)
64 	 * 2) 1 <= M <= vga->m[1] (usually 127)
65 	 * 3) 1 <= N <= vga->n[1] (usually 31)
66 	 * 4) 0 <= R <= vga->r[1]
67 	 *
68 	 * First determine R:
69 	 *	vga->f[1] < 2**R x Fout <= vga->f[1]*2
70 	 */
71 	for(r = 0; r <= vga->r[1]; r++){
72 		f = vga->f[0]*(1<<r);
73 		if(vga->f[1] < f && f <= vga->f[1]*2)
74 			vga->r[0] = r;
75 	}
76 	if(vga->r[0] > vga->r[1])
77 		error("%s: pclk %lud out of range\n", ctlr->name, vga->f[0]);
78 
79 	/*
80 	 * Now find the closest match for M and N.
81 	 */
82 	vga->d[0] = vga->f[0]+1;
83 	for(n = 1; n <= vga->n[1]; n++){
84 		trouble = vga->f[0]*(n+2)*(1<<vga->r[0]);
85 		trouble /= RefFreq;
86 		m = (trouble+0.5) - 2;
87 		if(m > vga->m[1])
88 			continue;
89 
90 		trouble = (m+2)*RefFreq;
91 		trouble /= (n+2)*(1<<vga->r[0]);
92 		f = trouble+0.5;
93 
94 		d = vga->f[0] - f;
95 		if(d < 0)
96 			d = -d;
97 		if(d <= vga->d[0]){
98 			vga->m[0] = m;
99 			vga->n[0] = n;
100 			vga->d[0] = d;
101 		}
102 	}
103 
104 	trouble = vga->f[0]*1.005;
105 	fmax = trouble;
106 	trouble = vga->f[0]*0.995;
107 	fmin = trouble;
108 	trouble = (vga->m[0]+2)*RefFreq;
109 	trouble /= (vga->n[0]+2)*(1<<vga->r[0]);
110 	f = trouble+0.5;
111 	if(fmin >= f || f >= fmax)
112 		error("%s: pclk %lud out of range\n", ctlr->name, vga->f[0]);
113 }
114 
115 static void
init(Vga * vga,Ctlr * ctlr)116 init(Vga* vga, Ctlr* ctlr)
117 {
118 	ulong pclk, x;
119 
120 	s3generic.init(vga, ctlr);
121 
122 	/*
123 	 * Clock bits. If the desired video clock is
124 	 * one of the two standard VGA clocks it can just be
125 	 * set using bits <3:2> of vga->misc, otherwise we
126 	 * need to programme the DCLK PLL.
127 	 */
128 	if(vga->mode->z > 8)
129 		error("depth %d not supported\n", vga->mode->z);
130 
131 	if(vga->f[0] == 0)
132 		vga->f[0] = vga->mode->frequency;
133 	vga->misc &= ~0x0C;
134 	if(vga->f[0] == VgaFreq0){
135 		/* nothing to do */;
136 	}
137 	else if(vga->f[0] == VgaFreq1)
138 		vga->misc |= 0x04;
139 	else{
140 		/*
141 		 * Part comes in -135MHz speed grade. In 8-bit mode
142 		 * the maximum DCLK is 80MHz. In 2x8-bit mode the maximum
143 		 * DCLK is 135MHz using the internal clock doubler.
144 		 */
145 		if((ctlr->flag & Hpclk2x8) && vga->mode->z == 8){
146 			pclk = 135000000;
147 			if(vga->f[0] > 80000000)
148 				ctlr->flag |= Upclk2x8;
149 		}
150 		else
151 			pclk = 80000000;
152 		if(vga->f[0] > pclk)
153 			error("%s: invalid pclk - %lud\n",
154 				ctlr->name, vga->f[0]);
155 
156 		vga->f[1] = 135000000;
157 		vga->r[1] = 3;
158 		vga->n[1] = 31;
159 		vga->m[1] = 127;
160 		trio64clock(vga, ctlr);
161 		vga->sequencer[0x12] = (vga->r[0]<<5)|vga->n[0];
162 		vga->sequencer[0x13] = vga->m[0];
163 		vga->misc |= 0x0C;
164 	}
165 
166 	/*
167 	 * Internal clock generator.
168 	 */
169 	vga->sequencer[0x15] &= ~0x31;
170 	vga->sequencer[0x15] |= 0x02;
171 	vga->sequencer[0x18] &= ~0x80;
172 	vga->crt[0x67] &= ~0xF2;
173 	if(ctlr->flag & Upclk2x8){
174 		vga->sequencer[0x15] |= 0x10;
175 		vga->sequencer[0x18] |= 0x80;
176 		/*
177 		 * There's a little strip of the border
178 		 * appears on the left in resolutions
179 		 * 1280 and above if the 0x02 bit isn't
180 		 * set (when it appears on the right...).
181 		 */
182 		vga->crt[0x67] |= 0x10;
183 	}
184 
185 	/*
186 	 * VLB address latch delay.
187 	 */
188 	if((vga->crt[0x36] & 0x03) == 0x01)
189 		vga->crt[0x58] &= ~0x08;
190 
191 	/*
192 	 * Start display FIFO fetch.
193 	 */
194 	x = vga->crt[0]-5;
195 	vga->crt[0x3B] = x;
196 	if(x & 0x100)
197 		vga->crt[0x5D] |= 0x40;
198 
199 	/*
200 	 * Display memory access control.
201 	 * Calculation of the M-parameter (Crt54) is
202 	 * memory-system and dot-clock dependent, the
203 	 * values below are guesses from dumping
204 	 * registers.
205 	 */
206 	vga->crt[0x60] = 0xFF;
207 	if(vga->mode->x <= 800)
208 		vga->crt[0x54] = 0xE8;
209 	else if(vga->mode->x <= 1024)
210 		vga->crt[0x54] = 0xA8;
211 	else
212 		vga->crt[0x54] = 0x00/*0x48*/;
213 
214 	ctlr->flag |= Finit;
215 }
216 
217 static void
load(Vga * vga,Ctlr * ctlr)218 load(Vga* vga, Ctlr* ctlr)
219 {
220 	ushort advfunc;
221 
222 	s3generic.load(vga, ctlr);
223 	vgaxo(Crtx, 0x60, vga->crt[0x60]);
224 	vgaxo(Crtx, 0x67, vga->crt[0x67]);
225 
226 	/*
227 	 * Load the PLL registers if necessary.
228 	 * Not sure if the variable-delay method of setting the
229 	 * PLL will work without a write here to vga->misc,
230 	 * so use the immediate-load method by toggling bit 5
231 	 * of Seq15 if necessary.
232 	 */
233 	vgaxo(Seqx, 0x12, vga->sequencer[0x12]);
234 	vgaxo(Seqx, 0x13, vga->sequencer[0x13]);
235 	if((vga->misc & 0x0C) == 0x0C)
236 		vgaxo(Seqx, 0x15, vga->sequencer[0x15]|0x20);
237 	vgaxo(Seqx, 0x15, vga->sequencer[0x15]);
238 	vgaxo(Seqx, 0x18, vga->sequencer[0x18]);
239 
240 	advfunc = 0x0000;
241 	if(ctlr->flag & Uenhanced)
242 		advfunc = 0x0001;
243 	outportw(0x4AE8, advfunc);
244 }
245 
246 static void
dump(Vga * vga,Ctlr * ctlr)247 dump(Vga* vga, Ctlr* ctlr)
248 {
249 	int i;
250 	ulong dclk, m, n, r;
251 
252 	s3generic.dump(vga, ctlr);
253 
254 	printitem(ctlr->name, "Seq08");
255 	for(i = 0x08; i < 0x19; i++)
256 		printreg(vga->sequencer[i]);
257 
258 	printitem(ctlr->name, "Crt2D");
259 	printreg(vga->crt[0x2D]);
260 	printreg(vga->crt[0x2E]);
261 	printreg(vga->crt[0x2F]);
262 
263 	n = vga->sequencer[0x12] & 0x1F;
264 	r = (vga->sequencer[0x12]>>5) & 0x03;
265 	m = vga->sequencer[0x13] & 0x7F;
266 	dclk = (m+2)*RefFreq;
267 	dclk /= (n+2)*(1<<r);
268 	printitem(ctlr->name, "dclk m n r");
269 	Bprint(&stdout, "%9ld %8ld       - %8ld %8ld\n", dclk, m, n, r);
270 }
271 
272 Ctlr trio64 = {
273 	"trio64",			/* name */
274 	snarf,				/* snarf */
275 	options,			/* options */
276 	init,				/* init */
277 	load,				/* load */
278 	dump,				/* dump */
279 };
280