1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4
5 #include "pci.h"
6 #include "vga.h"
7
8 /*
9 * 3Dfx.
10 */
11 enum {
12 dramInit0 = 0x018/4,
13 dramInit1 = 0x01C/4,
14 vgaInit0 = 0x028/4,
15 pllCtrl0 = 0x040/4,
16 pllCtrl1 = 0x044/4,
17 pllCtrl2 = 0x048/4,
18 dacMode = 0x04C/4,
19 vidProcCfg = 0x05C/4,
20 vidScreenSize = 0x098/4,
21 vidDesktopOverlayStride = 0x0E8/4,
22
23 Nior = 0x100/4,
24 };
25
26 typedef struct Tdfx {
27 ulong io;
28 Pcidev* pci;
29
30 ulong r[Nior];
31 } Tdfx;
32
33 static ulong
io32r(Tdfx * tdfx,int r)34 io32r(Tdfx* tdfx, int r)
35 {
36 return inportl(tdfx->io+(r*4));
37 }
38
39 static void
io32w(Tdfx * tdfx,int r,ulong l)40 io32w(Tdfx* tdfx, int r, ulong l)
41 {
42 outportl(tdfx->io+(r*4), l);
43 }
44
45 static void
snarf(Vga * vga,Ctlr * ctlr)46 snarf(Vga* vga, Ctlr* ctlr)
47 {
48 int i;
49 ulong v;
50 Tdfx *tdfx;
51
52 if(vga->private == nil){
53 tdfx = alloc(sizeof(Tdfx));
54 tdfx->pci = pcimatch(0, 0x121A, 0);
55 if(tdfx->pci == nil)
56 error("%s: not found\n", ctlr->name);
57 switch(tdfx->pci->did){
58 default:
59 error("%s: unknown chip - DID %4.4uX\n",
60 ctlr->name, tdfx->pci->did);
61 break;
62 case 0x0003: /* Banshee */
63 vga->f[1] = 270000000;
64 break;
65 case 0x0005: /* Avenger (a.k.a. Voodoo3) */
66 vga->f[1] = 300000000;
67 break;
68 case 0x0009: /* Voodoo5 */
69 vga->f[1] = 350000000;
70 break;
71 }
72 /*
73 * Frequency output of PLL's is given by
74 * fout = RefFreq*(n+2)/((m+2)*2^p)
75 * where there are 6 bits for m, 8 bits for n
76 * and 2 bits for p (k).
77 */
78 vga->m[1] = 64;
79 vga->n[1] = 256;
80 vga->p[1] = 4;
81
82 if((v = (tdfx->pci->mem[2].bar & ~0x3)) == 0)
83 error("%s: I/O not mapped\n", ctlr->name);
84 tdfx->io = v;
85
86 vga->private = tdfx;
87 }
88 tdfx = vga->private;
89
90 vga->crt[0x1A] = vgaxi(Crtx, 0x1A);
91 vga->crt[0x1B] = vgaxi(Crtx, 0x1B);
92 for(i = 0; i < Nior; i++)
93 tdfx->r[i] = io32r(tdfx, i);
94
95 /*
96 * If SDRAM then there's 16MB memory else it's SGRAM
97 * and can count it based on the power-on straps -
98 * chip size can be 8Mb or 16Mb, and there can be 4 or
99 * 8 of them.
100 */
101 vga->vma = tdfx->pci->mem[1].size;
102 if(tdfx->r[dramInit1] & 0x40000000)
103 vga->vmz = 16*1024*1024;
104 else{
105 if(tdfx->r[dramInit0] & 0x08000000)
106 i = 16*1024*1024/8;
107 else
108 i = 8*1024*1024/8;
109 if(tdfx->r[dramInit0] & 0x04000000)
110 i *= 8;
111 else
112 i *= 4;
113 vga->vmz = i;
114 }
115
116 ctlr->flag |= Fsnarf;
117 }
118
119 static void
options(Vga *,Ctlr * ctlr)120 options(Vga*, Ctlr* ctlr)
121 {
122 ctlr->flag |= Hlinear|Hclk2|Foptions;
123 }
124
125 static void
tdfxclock(Vga * vga,Ctlr *)126 tdfxclock(Vga* vga, Ctlr*)
127 {
128 int d, dmin;
129 uint f, m, n, p;
130
131 dmin = vga->f[0];
132 for(m = 1; m < vga->m[1]; m++){
133 for(n = 1; n < vga->n[1]; n++){
134 f = (RefFreq*(n+2))/(m+2);
135 for(p = 0; p < vga->p[1]; p++){
136 d = vga->f[0] - (f/(1<<p));
137 if(d < 0)
138 d = -d;
139 if(d >= dmin)
140 continue;
141 dmin = d;
142 vga->m[0] = m;
143 vga->n[0] = n;
144 vga->p[0] = p;
145 }
146 }
147 }
148 }
149
150 static void
init(Vga * vga,Ctlr * ctlr)151 init(Vga* vga, Ctlr* ctlr)
152 {
153 int x;
154 Mode *mode;
155 Tdfx *tdfx;
156
157 mode = vga->mode;
158 tdfx = vga->private;
159
160 if(vga->linear && (ctlr->flag & Hlinear))
161 ctlr->flag |= Ulinear;
162
163 /*
164 * Clock bits. If the desired video clock is
165 * one of the two standard VGA clocks or 50MHz it can just be
166 * set using bits <3:2> of vga->misc, otherwise we
167 * need to programme the PLL.
168 */
169 if(vga->f[0] == 0)
170 vga->f[0] = mode->frequency;
171 vga->misc &= ~0x0C;
172 if(vga->f[0] == VgaFreq0){
173 /* nothing to do */;
174 }
175 else if(vga->f[0] == VgaFreq1)
176 vga->misc |= 0x04;
177 else if(vga->f[0] == 50000000)
178 vga->misc |= 0x08;
179 else{
180 if(vga->f[0] > vga->f[1])
181 error("%s: invalid pclk - %lud\n",
182 ctlr->name, vga->f[0]);
183 if(vga->f[0] > 135000000 && (ctlr->flag & Hclk2)){
184 if(mode->x%16)
185 error("%s: f > 135MHz requires (x%%16) == 0\n",
186 ctlr->name);
187 ctlr->flag |= Uclk2;
188 }
189 tdfxclock(vga, ctlr);
190
191 tdfx->r[pllCtrl0] = (vga->n[0]<<8)|(vga->m[0]<<2)|vga->p[0];
192 vga->misc |= 0x0C;
193 }
194
195 /*
196 * Pixel format and memory stride.
197 */
198 tdfx->r[vidScreenSize] = (mode->y<<12)|mode->x;
199 tdfx->r[vidProcCfg] = 0x00000081;
200 switch(mode->z){
201 default:
202 error("%s: %d-bit mode not supported\n", ctlr->name, mode->z);
203 break;
204 case 8:
205 tdfx->r[vidDesktopOverlayStride] = mode->x;
206 break;
207 case 16:
208 tdfx->r[vidDesktopOverlayStride] = mode->x*2;
209 tdfx->r[vidProcCfg] |= 0x00040400;
210 break;
211 case 32:
212 tdfx->r[vidDesktopOverlayStride] = mode->x*4;
213 tdfx->r[vidProcCfg] |= 0x000C0400;
214 break;
215 }
216 tdfx->r[vgaInit0] = 0x140;
217
218 /*
219 * Adjust horizontal timing if doing two screen pixels per clock.
220 */
221 tdfx->r[dacMode] = 0;
222 if(ctlr->flag & Uclk2){
223 vga->crt[0x00] = ((mode->ht/2)>>3)-5;
224 vga->crt[0x01] = ((mode->x/2)>>3)-1;
225 vga->crt[0x02] = ((mode->shb/2)>>3)-1;
226
227 x = (mode->ehb/2)>>3;
228 vga->crt[0x03] = 0x80|(x & 0x1F);
229 vga->crt[0x04] = (mode->shs/2)>>3;
230 vga->crt[0x05] = ((mode->ehs/2)>>3) & 0x1F;
231 if(x & 0x20)
232 vga->crt[0x05] |= 0x80;
233
234 tdfx->r[dacMode] |= 0x01;
235 tdfx->r[vidProcCfg] |= 0x04000000;
236 }
237
238 /*
239 * Overflow.
240 */
241 vga->crt[0x1A] = 0x00;
242 if(vga->crt[0x00] & 0x100)
243 vga->crt[0x1A] |= 0x01;
244 if(vga->crt[0x01] & 0x100)
245 vga->crt[0x1A] |= 0x04;
246 if(vga->crt[0x03] & 0x100)
247 vga->crt[0x1A] |= 0x10;
248 x = mode->ehb;
249 if(ctlr->flag & Uclk2)
250 x /= 2;
251 if((x>>3) & 0x40)
252 vga->crt[0x1A] |= 0x20;
253 if(vga->crt[0x04] & 0x100)
254 vga->crt[0x1A] |= 0x40;
255 x = mode->ehs;
256 if(ctlr->flag & Uclk2)
257 x /= 2;
258 if((x>>3) & 0x20)
259 vga->crt[0x1A] |= 0x80;
260
261 vga->crt[0x1B] = 0x00;
262 if(vga->crt[0x06] & 0x400)
263 vga->crt[0x1B] |= 0x01;
264 if(vga->crt[0x12] & 0x400)
265 vga->crt[0x1B] |= 0x04;
266 if(vga->crt[0x15] & 0x400)
267 vga->crt[0x1B] |= 0x10;
268 if(vga->crt[0x10] & 0x400)
269 vga->crt[0x1B] |= 0x40;
270
271 vga->attribute[0x11] = Pblack;
272
273 ctlr->flag |= Finit;
274 }
275
276 static void
load(Vga * vga,Ctlr * ctlr)277 load(Vga* vga, Ctlr* ctlr)
278 {
279 Tdfx *tdfx;
280
281 vgaxo(Crtx, 0x1A, vga->crt[0x1A]);
282 vgaxo(Crtx, 0x1B, vga->crt[0x1B]);
283
284 tdfx = vga->private;
285 io32w(tdfx, dacMode, tdfx->r[dacMode]);
286 io32w(tdfx, vidScreenSize, tdfx->r[vidScreenSize]);
287 io32w(tdfx, vidDesktopOverlayStride, tdfx->r[vidDesktopOverlayStride]);
288 io32w(tdfx, vidProcCfg, tdfx->r[vidProcCfg]);
289 io32w(tdfx, vgaInit0, tdfx->r[vgaInit0]);
290
291 if((vga->misc & 0x0C) == 0x0C)
292 io32w(tdfx, pllCtrl0, tdfx->r[pllCtrl0]);
293
294 ctlr->flag |= Fload;
295 }
296
297 static uint
pllctrl(Tdfx * tdfx,int pll)298 pllctrl(Tdfx* tdfx, int pll)
299 {
300 uint k, m, n, r;
301
302 r = tdfx->r[pllCtrl0+pll];
303 k = r & 0x03;
304 m = (r>>2) & 0x3F;
305 n = (r>>8) & 0xFF;
306
307 return (RefFreq*(n+2))/((m+2)*(1<<k));
308 }
309
310 static void
dump(Vga * vga,Ctlr * ctlr)311 dump(Vga* vga, Ctlr* ctlr)
312 {
313 int i;
314 Tdfx *tdfx;
315
316 if((tdfx = vga->private) == nil)
317 return;
318
319 printitem(ctlr->name, "Crt1A");
320 printreg(vga->crt[0x1A]);
321 printreg(vga->crt[0x1B]);
322
323 Bprint(&stdout, "\n");
324 for(i = 0; i < Nior; i++)
325 Bprint(&stdout, "%s %2.2uX\t%.8luX\n",
326 ctlr->name, i*4, tdfx->r[i]);
327
328 printitem(ctlr->name, "pllCtrl");
329 Bprint(&stdout, "%9ud %8ud\n", pllctrl(tdfx, 0), pllctrl(tdfx, 1));
330 }
331
332 Ctlr tdfx = {
333 "3dfx", /* name */
334 snarf, /* snarf */
335 options, /* options */
336 init, /* init */
337 load, /* load */
338 dump, /* dump */
339 };
340
341 Ctlr tdfxhwgc = {
342 "3dfxhwgc", /* name */
343 0, /* snarf */
344 0, /* options */
345 0, /* init */
346 0, /* load */
347 0, /* dump */
348 };
349