]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/vga/mach32.c
exec(2): fix prototypes
[plan9front.git] / sys / src / cmd / aux / vga / mach32.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 Mach32. Some hope.
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         Advfunc         = 0x4AE8,       /* Advanced Function Control Register */
20         Clocksel        = 0x4AEE,       /* Clock Select Register */
21         Misc            = 0x36EE,       /* Miscellaneous Register */
22         Membndry        = 0x42EE,       /* Memory Boundary Register */
23         Memcfg          = 0x5EEE,       /* Memory Control Register */
24 };
25
26 typedef struct {
27         ushort  advfunc;
28         ushort  clocksel;
29         ushort  misc;
30         ushort  membndry;
31         ushort  memcfg;
32 } Mach32;
33
34 /*
35  * There are a number of possible clock generator chips for these
36  * boards, and I don't know how to find out which is installed, other
37  * than by looking at the board. So, pick a subset that will work for
38  * all.
39  */
40 typedef struct {
41         ulong   frequency;
42         uchar   b8;                     /* <6> - divide by 2 */
43         uchar   b9;                     /* <1> - bit <3> of frequency index */
44         uchar   be;                     /* <4> - bit <2> of frequency index */
45         uchar   misc;                   /* <3:2> - bits <1:0> of frequency index */
46 } Clock;
47
48 static Clock clocks[] = {
49         {  VgaFreq0,    0x40, 0x02, 0x00, 0x00, },
50         {  32000000,    0x00, 0x00, 0x10, 0x04, },
51         {  40000000,    0x00, 0x02, 0x10, 0x00, },
52         {  44900000,    0x00, 0x02, 0x00, 0x0C, },
53         {  65000000,    0x00, 0x02, 0x10, 0x0C, },
54         {  75000000,    0x00, 0x02, 0x10, 0x08, },
55         {         0, },
56 };
57         
58 static ulong atix;
59
60 static uchar
61 atixi(uchar index)
62 {
63         outportb(atix, index);
64         return inportb(atix+1);
65 }
66
67 static void
68 atixo(uchar index, uchar data)
69 {
70         outportw(atix, (data<<8)|index);
71 }
72
73 static void
74 atixinit(Vga* vga, Ctlr*)
75 {
76         uchar b;
77         Mach32 *mach32;
78
79         /*
80          * We could try to read in a part of the BIOS and try to determine
81          * the extended register address, but since we can't determine the offset value,
82          * we'll just have to assume the defaults all round.
83          */
84         atix = 0x1CE;
85
86         /*
87          * Unlock the ATI Extended Registers.
88          * We leave them unlocked from now on.
89          * Why does this chip have so many
90          * lock bits?
91          */
92         if((b = atixi(0xB8)) & 0x3F)
93                 atixo(0xB8, b & 0xC0);
94         b = atixi(0xAB);
95         atixo(0xAB, b & ~0x18);
96         atixo(0xB4, 0x00);
97         b = atixi(0xB9);
98         atixo(0xB9, b & ~0x80);
99         b = atixi(0xBE);
100         atixo(0xBE, b|0x09);
101
102         if(vga->private == 0)
103                 vga->private = alloc(sizeof(mach32));
104 }
105
106 static void
107 snarf(Vga* vga, Ctlr* ctlr)
108 {
109         int i;
110         Mach32 *mach32;
111
112         atixinit(vga, ctlr);
113         for(i = 0xA0; i < 0xC0; i++)
114                 vga->crt[i] = atixi(i);
115
116         mach32 = vga->private;
117         mach32->advfunc = inportw(Advfunc);
118         mach32->clocksel = inportw(Clocksel);
119         mach32->misc = inportw(Misc);
120         mach32->membndry = inportw(Membndry);
121         mach32->memcfg = inportw(Memcfg);
122
123         /*
124          * Memory size.
125          */
126         switch((mach32->misc>>2) & 0x03){
127
128         case 0:
129                 vga->vmz = 512*1024;
130                 break;
131
132         case 1:
133                 vga->vmz = 1024*1024;
134                 break;
135
136         case 2:
137                 vga->vmz = 2*1024*1024;
138                 break;
139
140         case 3:
141                 vga->vmz = 4*1024*1024;
142                 break;
143         }
144
145         ctlr->flag |= Fsnarf;
146 }
147
148 static void
149 options(Vga*, Ctlr* ctlr)
150 {
151         ctlr->flag |= Foptions;
152 }
153
154 static void
155 init(Vga* vga, Ctlr* ctlr)
156 {
157         Clock *clockp;
158         Mode *mode;
159
160         mode = vga->mode;
161
162         if(vga->f[0] == 0)
163                 vga->f[0] = vga->mode->frequency;
164         for(clockp = clocks; clockp->frequency; clockp++){
165                 if(clockp->frequency > vga->f[0]+100000)
166                         continue;
167                 if(clockp->frequency > vga->f[0]-100000)
168                         break;
169         }
170         if(clockp->frequency == 0)
171                 error("%s: no suitable clock for %lud\n",
172                         ctlr->name, vga->f[0]);
173
174         vga->crt[0xB0] &= 0xDA;
175         vga->crt[0xB1] &= 0x87;
176         vga->crt[0xB5] &= 0x7E;
177         vga->crt[0xB6] &= 0xE2;
178         vga->crt[0xB3] &= 0xAF;
179         vga->crt[0xA6] &= 0xFE;
180         vga->crt[0xA7] &= 0xF4;
181
182         /*
183          * 256-colour linear addressing.
184          */
185         if(mode->z == 8){
186                 vga->graphics[0x05] = 0x00;
187                 vga->attribute[0x10] &= ~0x40;
188                 vga->crt[0x13] = (mode->x/8)/2;
189                 vga->crt[0x14] = 0x00;
190                 vga->crt[0x17] = 0xE3;
191
192                 vga->crt[0xB0] |= 0x20;
193                 vga->crt[0xB6] |= 0x04;
194         }
195         vga->attribute[0x11] = 0x00;
196         vga->crt[0xB6] |= 0x01;
197         vga->crt[0xBE] &= ~0x04;
198
199         /*
200          * Do the clock index bits.
201          */
202         vga->crt[0xB9] &= 0xFD;
203         vga->crt[0xB8] &= 0x3F;
204         vga->crt[0xBE] &= 0xE5;
205
206         vga->crt[0xB8] |= clockp->b8;
207         vga->crt[0xB9] |= clockp->b9;
208         vga->crt[0xBE] |= clockp->be;
209         vga->misc |= clockp->misc;
210
211         if(vga->mode->interlace == 'v')
212                 vga->crt[0xBE] |= 0x02;
213
214         /*
215          * Turn off 128Kb CPU address bit so
216          * we only have a 64Kb aperture at 0xA0000.
217          */
218         vga->crt[0xBD] &= ~0x04;
219
220         ctlr->flag |= Finit;
221 }
222
223 static void
224 load(Vga* vga, Ctlr* ctlr)
225 {
226         ushort x;
227
228         /*
229          * Make sure we are in VGA mode,
230          * and that we have access to all the video memory through
231          * the 64Kb VGA aperture by disabling and linear aperture
232          * and memory boundary.
233          */
234         outportw(Clocksel, 0x0000);
235         x = inportw(Memcfg) & ~0x0003;
236         outportw(Memcfg, x);
237         outportw(Membndry, 0x0000);
238
239         atixo(0xB0, vga->crt[0xB0]);
240         atixo(0xB1, vga->crt[0xB1]);
241         atixo(0xB5, vga->crt[0xB5]);
242         atixo(0xB6, vga->crt[0xB6]);
243         atixo(0xB3, vga->crt[0xB3]);
244         atixo(0xA6, vga->crt[0xA6]);
245         atixo(0xA7, vga->crt[0xA7]);
246         atixo(0xB8, vga->crt[0xB8]);
247         atixo(0xB9, vga->crt[0xB9]);
248         atixo(0xBE, vga->crt[0xBE]);
249         vgao(MiscW, vga->misc);
250
251         ctlr->flag |= Fload;
252 }
253
254 static void
255 dump(Vga* vga, Ctlr* ctlr)
256 {
257         int i;
258         Mach32 *mach32;
259
260         printitem(ctlr->name, "ATIX");
261         for(i = 0xA0; i < 0xC0; i++)
262                 printreg(vga->crt[i]);
263
264         if((mach32 = vga->private) == 0)
265                 return;
266
267         printitem(ctlr->name, "ADVFUNC");
268         Bprint(&stdout, "%.4ux\n", mach32->advfunc);
269         printitem(ctlr->name, "CLOCKSEL");
270         Bprint(&stdout, "%.4ux\n", mach32->clocksel);
271         printitem(ctlr->name, "MISC");
272         Bprint(&stdout, "%.4ux\n", mach32->misc);
273         printitem(ctlr->name, "MEMBNDRY");
274         Bprint(&stdout, "%.4ux\n", mach32->membndry);
275         printitem(ctlr->name, "MEMCFG");
276         Bprint(&stdout, "%.4ux\n", mach32->memcfg);
277 }
278
279 Ctlr mach32 = {
280         "mach32",                       /* name */
281         snarf,                          /* snarf */
282         options,                        /* options */
283         init,                           /* init */
284         load,                           /* load */
285         dump,                           /* dump */
286 };