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