diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/aux/vga/mach32.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/vga/mach32.c')
-rwxr-xr-x | sys/src/cmd/aux/vga/mach32.c | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/vga/mach32.c b/sys/src/cmd/aux/vga/mach32.c new file mode 100755 index 000000000..e183a2da2 --- /dev/null +++ b/sys/src/cmd/aux/vga/mach32.c @@ -0,0 +1,286 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#include "pci.h" +#include "vga.h" + +/* + * ATI Mach32. Some hope. + * No support for accelerator so can only do up to 1024x768. + * + * All ATI Extended Registers are addressed using the modified index + * index = (0x02<<6)|(index & 0x3F); + * so registers 0x00->0x3F map to 0x80->0xBF, but we will only ever + * look at a few in the range 0xA0->0xBF. In this way we can stash + * them in the vga->crt[] array. + */ +enum { + Advfunc = 0x4AE8, /* Advanced Function Control Register */ + Clocksel = 0x4AEE, /* Clock Select Register */ + Misc = 0x36EE, /* Miscellaneous Register */ + Membndry = 0x42EE, /* Memory Boundary Register */ + Memcfg = 0x5EEE, /* Memory Control Register */ +}; + +typedef struct { + ushort advfunc; + ushort clocksel; + ushort misc; + ushort membndry; + ushort memcfg; +} Mach32; + +/* + * There are a number of possible clock generator chips for these + * boards, and I don't know how to find out which is installed, other + * than by looking at the board. So, pick a subset that will work for + * all. + */ +typedef struct { + ulong frequency; + uchar b8; /* <6> - divide by 2 */ + uchar b9; /* <1> - bit <3> of frequency index */ + uchar be; /* <4> - bit <2> of frequency index */ + uchar misc; /* <3:2> - bits <1:0> of frequency index */ +} Clock; + +static Clock clocks[] = { + { VgaFreq0, 0x40, 0x02, 0x00, 0x00, }, + { 32000000, 0x00, 0x00, 0x10, 0x04, }, + { 40000000, 0x00, 0x02, 0x10, 0x00, }, + { 44900000, 0x00, 0x02, 0x00, 0x0C, }, + { 65000000, 0x00, 0x02, 0x10, 0x0C, }, + { 75000000, 0x00, 0x02, 0x10, 0x08, }, + { 0, }, +}; + +static ulong atix; + +static uchar +atixi(uchar index) +{ + outportb(atix, index); + return inportb(atix+1); +} + +static void +atixo(uchar index, uchar data) +{ + outportw(atix, (data<<8)|index); +} + +static void +atixinit(Vga* vga, Ctlr*) +{ + uchar b; + Mach32 *mach32; + + /* + * We could try to read in a part of the BIOS and try to determine + * the extended register address, but since we can't determine the offset value, + * we'll just have to assume the defaults all round. + */ + atix = 0x1CE; + + /* + * Unlock the ATI Extended Registers. + * We leave them unlocked from now on. + * Why does this chip have so many + * lock bits? + */ + if((b = atixi(0xB8)) & 0x3F) + atixo(0xB8, b & 0xC0); + b = atixi(0xAB); + atixo(0xAB, b & ~0x18); + atixo(0xB4, 0x00); + b = atixi(0xB9); + atixo(0xB9, b & ~0x80); + b = atixi(0xBE); + atixo(0xBE, b|0x09); + + if(vga->private == 0) + vga->private = alloc(sizeof(mach32)); +} + +static void +snarf(Vga* vga, Ctlr* ctlr) +{ + int i; + Mach32 *mach32; + + atixinit(vga, ctlr); + for(i = 0xA0; i < 0xC0; i++) + vga->crt[i] = atixi(i); + + mach32 = vga->private; + mach32->advfunc = inportw(Advfunc); + mach32->clocksel = inportw(Clocksel); + mach32->misc = inportw(Misc); + mach32->membndry = inportw(Membndry); + mach32->memcfg = inportw(Memcfg); + + /* + * Memory size. + */ + switch((mach32->misc>>2) & 0x03){ + + case 0: + vga->vmz = 512*1024; + break; + + case 1: + vga->vmz = 1024*1024; + break; + + case 2: + vga->vmz = 2*1024*1024; + break; + + case 3: + vga->vmz = 4*1024*1024; + break; + } + + ctlr->flag |= Fsnarf; +} + +static void +options(Vga*, Ctlr* ctlr) +{ + ctlr->flag |= Foptions; +} + +static void +init(Vga* vga, Ctlr* ctlr) +{ + Clock *clockp; + Mode *mode; + + mode = vga->mode; + + if(vga->f[0] == 0) + vga->f[0] = vga->mode->frequency; + for(clockp = clocks; clockp->frequency; clockp++){ + if(clockp->frequency > vga->f[0]+100000) + continue; + if(clockp->frequency > vga->f[0]-100000) + break; + } + if(clockp->frequency == 0) + error("%s: no suitable clock for %lud\n", + ctlr->name, vga->f[0]); + + vga->crt[0xB0] &= 0xDA; + vga->crt[0xB1] &= 0x87; + vga->crt[0xB5] &= 0x7E; + vga->crt[0xB6] &= 0xE2; + vga->crt[0xB3] &= 0xAF; + vga->crt[0xA6] &= 0xFE; + vga->crt[0xA7] &= 0xF4; + + /* + * 256-colour linear addressing. + */ + if(mode->z == 8){ + vga->graphics[0x05] = 0x00; + vga->attribute[0x10] &= ~0x40; + vga->crt[0x13] = (mode->x/8)/2; + vga->crt[0x14] = 0x00; + vga->crt[0x17] = 0xE3; + + vga->crt[0xB0] |= 0x20; + vga->crt[0xB6] |= 0x04; + } + vga->attribute[0x11] = 0x00; + vga->crt[0xB6] |= 0x01; + vga->crt[0xBE] &= ~0x04; + + /* + * Do the clock index bits. + */ + vga->crt[0xB9] &= 0xFD; + vga->crt[0xB8] &= 0x3F; + vga->crt[0xBE] &= 0xE5; + + vga->crt[0xB8] |= clockp->b8; + vga->crt[0xB9] |= clockp->b9; + vga->crt[0xBE] |= clockp->be; + vga->misc |= clockp->misc; + + if(vga->mode->interlace == 'v') + vga->crt[0xBE] |= 0x02; + + /* + * Turn off 128Kb CPU address bit so + * we only have a 64Kb aperture at 0xA0000. + */ + vga->crt[0xBD] &= ~0x04; + + ctlr->flag |= Finit; +} + +static void +load(Vga* vga, Ctlr* ctlr) +{ + ushort x; + + /* + * Make sure we are in VGA mode, + * and that we have access to all the video memory through + * the 64Kb VGA aperture by disabling and linear aperture + * and memory boundary. + */ + outportw(Clocksel, 0x0000); + x = inportw(Memcfg) & ~0x0003; + outportw(Memcfg, x); + outportw(Membndry, 0x0000); + + atixo(0xB0, vga->crt[0xB0]); + atixo(0xB1, vga->crt[0xB1]); + atixo(0xB5, vga->crt[0xB5]); + atixo(0xB6, vga->crt[0xB6]); + atixo(0xB3, vga->crt[0xB3]); + atixo(0xA6, vga->crt[0xA6]); + atixo(0xA7, vga->crt[0xA7]); + atixo(0xB8, vga->crt[0xB8]); + atixo(0xB9, vga->crt[0xB9]); + atixo(0xBE, vga->crt[0xBE]); + vgao(MiscW, vga->misc); + + ctlr->flag |= Fload; +} + +static void +dump(Vga* vga, Ctlr* ctlr) +{ + int i; + Mach32 *mach32; + + printitem(ctlr->name, "ATIX"); + for(i = 0xA0; i < 0xC0; i++) + printreg(vga->crt[i]); + + if((mach32 = vga->private) == 0) + return; + + printitem(ctlr->name, "ADVFUNC"); + Bprint(&stdout, "%.4ux\n", mach32->advfunc); + printitem(ctlr->name, "CLOCKSEL"); + Bprint(&stdout, "%.4ux\n", mach32->clocksel); + printitem(ctlr->name, "MISC"); + Bprint(&stdout, "%.4ux\n", mach32->misc); + printitem(ctlr->name, "MEMBNDRY"); + Bprint(&stdout, "%.4ux\n", mach32->membndry); + printitem(ctlr->name, "MEMCFG"); + Bprint(&stdout, "%.4ux\n", mach32->memcfg); +} + +Ctlr mach32 = { + "mach32", /* name */ + snarf, /* snarf */ + options, /* options */ + init, /* init */ + load, /* load */ + dump, /* dump */ +}; |