summaryrefslogtreecommitdiff
path: root/sys/src/cmd/aux/vga/mach32.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /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-xsys/src/cmd/aux/vga/mach32.c286
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 */
+};