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 }; 373