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