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