]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/vga/mach64.c
Import sources from 2011-03-30 iso image
[plan9front.git] / sys / src / cmd / aux / vga / mach64.c
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
122 atixi(uchar index)
123 {
124         outportb(atix, index);
125         return inportb(atix+1);
126 }
127
128 static void
129 atixo(uchar index, uchar data)
130 {
131         outportw(atix, (data<<8)|index);
132 }
133
134 static void
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
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
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
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
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 };