1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4
5 #include "pci.h"
6 #include "vga.h"
7
8 /*
9 * ATI Mach64. Some hope. Kind of like a Mach32.
10 * No support for accelerator so can only do up to 1024x768.
11 *
12 * All ATI Extended Registers are addressed using the modified index
13 * index = (0x02<<6)|(index & 0x3F);
14 * so registers 0x00->0x3F map to 0x80->0xBF, but we will only ever
15 * look at a few in the range 0xA0->0xBF. In this way we can stash
16 * them in the vga->crt[] array.
17 */
18 enum {
19 Configcntl = 0x6AEC, /* Configuration control */
20 Configstat = 0x72EC, /* Configuration status */
21 Memcntl = 0x52EC, /* Memory control */
22 Scratch1 = 0x46EC, /* Scratch Register (BIOS info) */
23 };
24
25 typedef struct {
26 ulong configcntl;
27 ulong configstat;
28 ulong memcntl;
29 ulong scratch1;
30 } Mach64;
31
32 /*
33 * There are a number of possible clock generator chips for these
34 * boards. We can divide any frequency by 2 (bit<6> of b8).
35 */
36 typedef struct {
37 ulong frequency;
38 uchar be; /* <4> - bit<3> of frequency index */
39 uchar b9; /* <1> - bit<2> of frequency index */
40 uchar genmo; /* <3:2> - bits <1:0> of frequency index */
41 } Pclk;
42
43 enum {
44 Npclkx = 16, /* number of clock entries per table */
45 };
46
47 /*
48 * ATI18811-0
49 */
50 static Pclk ati188110[Npclkx] = {
51 { 42950000, 0x00, 0x00, 0x00 },
52 { 48770000, 0x00, 0x00, 0x04 },
53 { 92400000, 0x00, 0x00, 0x08 },
54 { 36000000, 0x00, 0x00, 0x0C },
55 { 50350000, 0x00, 0x02, 0x00 },
56 { 56640000, 0x00, 0x02, 0x04 },
57 { 0, 0x00, 0x02, 0x08 },
58 { 44900000, 0x00, 0x02, 0x0C },
59 { 30240000, 0x10, 0x00, 0x00 },
60 { 32000000, 0x10, 0x00, 0x04 },
61 { 110000000, 0x10, 0x00, 0x08 },
62 { 80000000, 0x10, 0x00, 0x0C },
63 { 39910000, 0x10, 0x02, 0x00 },
64 { 44900000, 0x10, 0x02, 0x04 },
65 { 75000000, 0x10, 0x02, 0x08 },
66 { 65000000, 0x10, 0x02, 0x0C },
67 };
68
69 /*
70 * ATI18811-1, ATI18811-2
71 * PCLK_TABLE = 0 in Mach64 speak.
72 */
73 static Pclk ati188111[Npclkx] = {
74 { 100000000, 0x00, 0x00, 0x00 },
75 { 126000000, 0x00, 0x00, 0x04 },
76 { 92400000, 0x00, 0x00, 0x08 },
77 { 36000000, 0x00, 0x00, 0x0C },
78 { 50350000, 0x00, 0x02, 0x00 },
79 { 56640000, 0x00, 0x02, 0x04 },
80 { 0, 0x00, 0x02, 0x08 },
81 { 44900000, 0x00, 0x02, 0x0C },
82 { 135000000, 0x10, 0x00, 0x00 },
83 { 32000000, 0x10, 0x00, 0x04 },
84 { 110000000, 0x10, 0x00, 0x08 },
85 { 80000000, 0x10, 0x00, 0x0C },
86 { 39910000, 0x10, 0x02, 0x00 },
87 { 44900000, 0x10, 0x02, 0x04 },
88 { 75000000, 0x10, 0x02, 0x08 },
89 { 65000000, 0x10, 0x02, 0x0C },
90 };
91
92 /*
93 * ATI18818
94 * The first four entries are programmable and the default
95 * settings are either those below or those below divided by 2
96 * (PCLK_TABLE = 1 and PCLK_TABLE = 2 respectively in Mach64
97 * speak).
98 */
99 static Pclk ati18818[Npclkx] = {
100 { 50350000, 0x00, 0x00, 0x00 },
101 { 56640000, 0x00, 0x00, 0x04 },
102 { 63000000, 0x00, 0x00, 0x08 },
103 { 72000000, 0x00, 0x00, 0x0C },
104 { 40000000, 0x00, 0x02, 0x00 },
105 { 44900000, 0x00, 0x02, 0x04 },
106 { 49500000, 0x00, 0x02, 0x08 },
107 { 50000000, 0x00, 0x02, 0x0C },
108 { 0, 0x10, 0x00, 0x00 },
109 { 110000000, 0x10, 0x00, 0x04 },
110 { 126000000, 0x10, 0x00, 0x08 },
111 { 135000000, 0x10, 0x00, 0x0C },
112 { 0, 0x10, 0x02, 0x00 },
113 { 80000000, 0x10, 0x02, 0x04 },
114 { 75000000, 0x10, 0x02, 0x08 },
115 { 65000000, 0x10, 0x02, 0x0C },
116 };
117
118 static Pclk *pclkp; /* which clock chip we are using */
119 static ulong atix; /* index to extended regsiters */
120
121 static uchar
atixi(uchar index)122 atixi(uchar index)
123 {
124 outportb(atix, index);
125 return inportb(atix+1);
126 }
127
128 static void
atixo(uchar index,uchar data)129 atixo(uchar index, uchar data)
130 {
131 outportw(atix, (data<<8)|index);
132 }
133
134 static void
atixinit(Vga * vga,Ctlr *)135 atixinit(Vga* vga, Ctlr*)
136 {
137 uchar b;
138
139 /*
140 * Set the I/O address and offset for the ATI
141 * extended registers to something we know about.
142 */
143 if(atix == 0){
144 outportw(Grx, (0xCE<<8)|0x50);
145 outportw(Grx, (0x81<<8)|0x51);
146 atix = 0x1CE;
147 }
148
149 /*
150 * Unlock the ATI Extended Registers.
151 * We leave them unlocked from now on.
152 * Why does this chip have so many
153 * lock bits?
154 */
155 if((b = atixi(0xB8)) & 0x3F)
156 atixo(0xB8, b & 0xC0);
157 b = atixi(0xAB);
158 atixo(0xAB, b & ~0x18);
159 atixo(0xB4, 0x00);
160 b = atixi(0xB9);
161 atixo(0xB9, b & ~0x80);
162 b = atixi(0xBE);
163 atixo(0xBE, b|0x09);
164
165 if(vga->private == 0)
166 vga->private = alloc(sizeof(Mach64));
167 }
168
169 static void
snarf(Vga * vga,Ctlr * ctlr)170 snarf(Vga* vga, Ctlr* ctlr)
171 {
172 int i;
173 Mach64 *mach64;
174
175 atixinit(vga, ctlr);
176 for(i = 0xA0; i < 0xC0; i++)
177 vga->crt[i] = atixi(i);
178
179 mach64 = vga->private;
180 mach64->configcntl = inportl(Configcntl);
181 mach64->configstat = inportl(Configstat);
182 mach64->memcntl = inportl(Memcntl);
183 mach64->scratch1 = inportl(Scratch1);
184
185 /*
186 * Memory size.
187 */
188 switch(mach64->memcntl & 0x07){
189
190 case 0:
191 vga->vmz = 512*1024;
192 break;
193
194 case 1:
195 vga->vmz = 1024*1024;
196 break;
197
198 case 2:
199 vga->vmz = 2*1024*1024;
200 break;
201
202 case 3:
203 vga->vmz = 4*1024*1024;
204 break;
205
206 case 4:
207 vga->vmz = 6*1024*1024;
208 break;
209
210 case 5:
211 vga->vmz = 8*1024*1024;
212 break;
213 }
214
215 ctlr->flag |= Fsnarf;
216 }
217
218 static void
init(Vga * vga,Ctlr * ctlr)219 init(Vga* vga, Ctlr* ctlr)
220 {
221 Mode *mode;
222 int f, divisor, index;
223
224 mode = vga->mode;
225
226 /*
227 * Must somehow determine which clock chip to use here.
228 * For now, punt and assume ATI18818.
229 */
230 pclkp = ati18818;
231 if(pclkp == 0)
232 error("%s: can't determine clock chip\n", ctlr->name);
233
234 if(vga->f[0] == 0)
235 vga->f[0] = vga->mode->frequency;
236
237 /*
238 * Find a clock frequency close to what we want.
239 * 'Close' is within 1MHz.
240 */
241 for(divisor = 0, index = 0; index < Npclkx; index++, divisor = 0){
242 divisor = 1;
243 f = pclkp[index].frequency/divisor;
244 if(f < vga->f[0]+1000000 && f >= vga->f[0]-1000000)
245 break;
246
247 divisor = 2;
248 f /= divisor;
249 if(f < vga->f[0]+1000000 && f >= vga->f[0]-1000000)
250 break;
251 }
252 if(divisor == 0)
253 error("%s: no suitable clock for %lud\n",
254 ctlr->name, vga->f[0]);
255
256 vga->d[0] = divisor;
257 vga->i[0] = index;
258
259 vga->crt[0xB0] &= 0xDA;
260 vga->crt[0xB1] &= 0x87;
261 vga->crt[0xB5] &= 0x7E;
262 vga->crt[0xB6] &= 0xE2;
263 vga->crt[0xB3] &= 0xAF;
264 vga->crt[0xA6] &= 0xFE;
265 vga->crt[0xA7] &= 0xF4;
266
267 /*
268 * 256-colour linear addressing.
269 */
270 if(mode->z == 8){
271 vga->graphics[0x05] = 0x00;
272 vga->attribute[0x10] &= ~0x40;
273 vga->crt[0x13] = (mode->x/8)/2;
274 vga->crt[0x14] = 0x00;
275 vga->crt[0x17] = 0xE3;
276
277 vga->crt[0xB0] |= 0x20;
278 vga->crt[0xB6] |= 0x04;
279 }
280 vga->attribute[0x11] = 0x00;
281 vga->crt[0xB6] |= 0x01;
282 vga->crt[0xBE] &= ~0x04;
283
284 /*
285 * Do the clock index bits.
286 */
287 vga->crt[0xB8] &= 0x3F;
288 vga->crt[0xB9] &= 0xFD;
289 vga->crt[0xBE] &= 0xE5;
290
291 if(vga->d[0] == 2)
292 vga->crt[0xB8] |= 0x40;
293 vga->crt[0xB9] |= pclkp[vga->i[0]].b9;
294 vga->crt[0xBE] |= pclkp[vga->i[0]].be;
295 vga->misc |= pclkp[vga->i[0]].genmo;
296
297 if(vga->mode->interlace == 'v')
298 vga->crt[0xBE] |= 0x02;
299
300 /*
301 * Turn off 128Kb CPU address bit so
302 * we only have a 64Kb aperture at 0xA0000.
303 */
304 vga->crt[0xBD] &= ~0x04;
305
306 ctlr->type = mach32.name;
307
308 /*
309 * The Mach64 can only address 1Mb in VGA mode
310 */
311 vga->vmz = 1*1024*1024;
312
313 ctlr->flag |= Finit;
314 }
315
316 static void
load(Vga * vga,Ctlr * ctlr)317 load(Vga* vga, Ctlr* ctlr)
318 {
319 /*
320 * We should probably do something here to make sure we that we
321 * have access to all the video memory through the 64Kb VGA aperture
322 * by disabling and linear aperture and memory boundary and then
323 * enabling the VGA controller.
324 * But for now, let's just assume it's ok, the Mach64 documentation
325 * is just as clear as the Mach32 documentation.
326 */
327 atixo(0xB0, vga->crt[0xB0]);
328 atixo(0xB1, vga->crt[0xB1]);
329 atixo(0xB5, vga->crt[0xB5]);
330 atixo(0xB6, vga->crt[0xB6]);
331 atixo(0xB3, vga->crt[0xB3]);
332 atixo(0xA6, vga->crt[0xA6]);
333 atixo(0xA7, vga->crt[0xA7]);
334 atixo(0xB8, vga->crt[0xB8]);
335 atixo(0xB9, vga->crt[0xB9]);
336 atixo(0xBE, vga->crt[0xBE]);
337 vgao(MiscW, vga->misc);
338
339 ctlr->flag |= Fload;
340 }
341
342 static void
dump(Vga * vga,Ctlr * ctlr)343 dump(Vga* vga, Ctlr* ctlr)
344 {
345 int i;
346 Mach64 *mach64;
347
348 printitem(ctlr->name, "ATIX");
349 for(i = 0xA0; i < 0xC0; i++)
350 printreg(vga->crt[i]);
351
352 if((mach64 = vga->private) == 0)
353 return;
354
355 printitem(ctlr->name, "CONFIGCNTL");
356 Bprint(&stdout, "%.8lux\n", mach64->configcntl);
357 printitem(ctlr->name, "CONFIGSTAT");
358 Bprint(&stdout, "%.8lux\n", mach64->configstat);
359 printitem(ctlr->name, "MEMCNTL");
360 Bprint(&stdout, "%.8lux\n", mach64->memcntl);
361 printitem(ctlr->name, "SCRATCH1");
362 Bprint(&stdout, "%.8lux\n", mach64->scratch1);
363 }
364
365 Ctlr mach64 = {
366 "mach64", /* name */
367 snarf, /* snarf */
368 0, /* options */
369 init, /* init */
370 load, /* load */
371 dump, /* dump */
372 };
373