summaryrefslogtreecommitdiff
path: root/sys/src/cmd/aux/vga/clgd542x.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/clgd542x.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/vga/clgd542x.c')
-rwxr-xr-xsys/src/cmd/aux/vga/clgd542x.c337
1 files changed, 337 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/vga/clgd542x.c b/sys/src/cmd/aux/vga/clgd542x.c
new file mode 100755
index 000000000..3e5c60e21
--- /dev/null
+++ b/sys/src/cmd/aux/vga/clgd542x.c
@@ -0,0 +1,337 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+#include "pci.h"
+#include "vga.h"
+
+/*
+ * Cirrus Logic True Color VGA Family - CL-GD542X.
+ * Also works for Alpine VGA Family - CL-GD543X.
+ * Just the basics. BUGS:
+ * the added capabilities of the 543X aren't used.
+ */
+
+typedef struct {
+ uchar id; /* Id */
+ ulong vclk; /* Maximum dot clock */
+} Gd542x;
+
+static Gd542x family[] = {
+ { 0x88, 75000000, }, /* CL-GD5420 */
+ { 0x8C, 80000000, }, /* CL-GD5422 */
+ { 0x94, 80000000, }, /* CL-GD5424 */
+ { 0x90, 80000000, }, /* CL-GD5426 */
+ { 0x98, 80000000, }, /* CL-GD5428 */
+ { 0x9C, 86000000, }, /* CL-GD5429 */
+ { 0xA0, 86000000, }, /* CL-GD5430 */
+ { 0xA8, 86000000, }, /* CL-GD5434 */
+
+ { 0xAC, 135000000, }, /* CL-GD5436 */
+ { 0xB8, 135000000, }, /* CL-GD5446 */
+ { 0xBC, 135000000, }, /* CL-GD5480 */
+
+ { 0x30, 80000000, }, /* CL-GD7543 */
+
+ { 0x00, },
+};
+
+static Gd542x*
+identify(Vga* vga, Ctlr* ctlr)
+{
+ Gd542x *gd542x;
+ uchar id;
+
+ id = vga->crt[0x27] & ~0x03;
+ for(gd542x = &family[0]; gd542x->id; gd542x++){
+ if(gd542x->id == id)
+ return gd542x;
+ }
+
+ error("%s: unknown chip id - 0x%2.2X\n", ctlr->name, vga->crt[0x27]);
+ return 0;
+}
+
+static void
+snarf(Vga* vga, Ctlr* ctlr)
+{
+ int i;
+ Gd542x *gd542x;
+
+ /*
+ * Unlock extended registers.
+ */
+ vgaxo(Seqx, 0x06, 0x12);
+
+ /*
+ * Save all the registers, even though we'll only
+ * change a handful.
+ */
+ for(i = 0x06; i < 0x20; i++)
+ vga->sequencer[i] = vgaxi(Seqx, i);
+
+ for(i = 0x09; i < 0x3A; i++)
+ vga->graphics[i] = vgaxi(Grx, i);
+
+ for(i = 0x19; i < 0x1E; i++)
+ vga->crt[i] = vgaxi(Crtx, i);
+
+ vga->crt[0x27] = vgaxi(Crtx, 0x27);
+
+ /*
+ * Hack for Hidden DAC Register. Do 4 dummy reads
+ * of Pixmask first.
+ */
+ for(i = 0; i < 4; i++)
+ vgai(Pixmask);
+ vga->crt[0x28] = vgai(Pixmask);
+
+ i = 0;
+ switch(vga->crt[0x27] & ~0x03){
+
+ case 0x88: /* CL-GD5420 */
+ case 0x8C: /* CL-GD5422 */
+ case 0x94: /* CL-GD5424 */
+ case 0x80: /* CL-GD5425 */
+ case 0x90: /* CL-GD5426 */
+ case 0x98: /* CL-GD5427 */
+ case 0x9C: /* CL-GD5429 */
+ /*
+ * The BIOS leaves the memory size in Seq0A, bits 4 and 3.
+ * See Technical Reference Manual Appendix E1, Section 1.3.2.
+ *
+ * The storage area for the 64x64 cursors is the last 16Kb of
+ * display memory.
+ */
+ i = (vga->sequencer[0x0A]>>3) & 0x03;
+ break;
+
+ case 0xA0: /* CL-GD5430 */
+ case 0xA8: /* CL-GD5434 */
+ case 0xAC: /* CL-GD5436 */
+ case 0xB8: /* CL-GD5446 */
+ case 0x30: /* CL-GD7543 */
+ /*
+ * Attempt to intuit the memory size from the DRAM control
+ * register. Minimum is 512KB.
+ * If DRAM bank switching is on then there's double.
+ */
+ i = (vga->sequencer[0x0F]>>3) & 0x03;
+ if(vga->sequencer[0x0F] & 0x80)
+ i++;
+
+ /*
+ * If it's a PCI card, can do linear.
+ * Most of the Cirrus chips can do linear addressing with
+ * all the different buses, but it can get messy. It's easy
+ * to cut PCI on the CLGD543x chips out of the pack.
+ */
+ if(((vga->sequencer[0x17]>>3) & 0x07) == 0x04)
+ ctlr->flag |= Hlinear;
+ break;
+ case 0xBC: /* CL-GD5480 */
+ i = 2; /* 1024 = 256<<2 */
+ if((vga->sequencer[0x0F] & 0x18) == 0x18){
+ i <<= 1; /* 2048 = 256<<3 */
+ if(vga->sequencer[0x0F] & 0x80)
+ i <<= 2; /* 2048 = 256<<4 */
+ }
+ if(vga->sequencer[0x17] & 0x80)
+ i <<= 1;
+ ctlr->flag |= Hlinear;
+ break;
+
+ default: /* uh, ah dunno */
+ break;
+ }
+
+ if(vga->linear && (ctlr->flag & Hlinear)){
+ vga->vmz = 16*1024*1024;
+ vga->vma = 16*1024*1024;
+ ctlr->flag |= Ulinear;
+ }
+ else
+ vga->vmz = (256<<i)*1024;
+
+ gd542x = identify(vga, ctlr);
+ if(vga->f[1] == 0 || vga->f[1] > gd542x->vclk)
+ vga->f[1] = gd542x->vclk;
+ ctlr->flag |= Fsnarf;
+}
+
+void
+clgd54xxclock(Vga* vga, Ctlr* ctlr)
+{
+ int f;
+ ulong d, dmin, fmin, n, nmin, p;
+
+ trace("%s->init->clgd54xxclock\n", ctlr->name);
+
+ /*
+ * Athough the Technical Reference Manual says only a handful
+ * of frequencies are tested, it also gives the following formula
+ * which can be used to generate any frequency within spec.,
+ * including the tested ones.
+ *
+ * Numerator is 7-bits, denominator 5-bits.
+ * Guess from the Technical Reference Manual that
+ * The post divisor is 1 for vclk<40MHz.
+ *
+ * Look for values of n and d and p that give
+ * the least error for
+ * vclk = (RefFreq*n)/(d*(1+p));
+ *
+ * There's nothing like brute force and ignorance.
+ */
+ fmin = vga->f[0];
+ nmin = 69;
+ dmin = 24;
+ if(vga->f[0] >= 40000000)
+ p = 0;
+ else
+ p = 1;
+ for(n = 1; n < 128; n++){
+ for(d = 1; d < 32; d++){
+ f = vga->f[0] - (RefFreq*n)/(d*(1+p));
+ if(f < 0)
+ f = -f;
+ if(f <= fmin){
+ fmin = f;
+ nmin = n;
+ dmin = d;
+ }
+ }
+ }
+
+ vga->f[0] = (RefFreq*nmin)/(dmin*(1+p));
+ vga->d[0] = dmin;
+ vga->n[0] = nmin;
+ vga->p[0] = p;
+}
+
+void
+init(Vga* vga, Ctlr* ctlr)
+{
+ Mode *mode;
+ Gd542x *gd542x;
+ ushort x;
+
+ mode = vga->mode;
+ gd542x = identify(vga, ctlr);
+
+ if(vga->f[0] == 0)
+ vga->f[0] = vga->mode->frequency;
+ if(vga->f[0] > gd542x->vclk)
+ error("%s: pclk %lud too high (> %lud)\n",
+ ctlr->name, vga->f[0], gd542x->vclk);
+
+ if(mode->z > 8)
+ error("%s: depth %d not supported\n", ctlr->name, mode->z);
+
+ /*
+ * VCLK3
+ */
+ clgd54xxclock(vga, ctlr);
+ vga->misc |= 0x0C;
+ vga->sequencer[0x0E] = vga->n[0];
+ vga->sequencer[0x1E] = (vga->d[0]<<1)|vga->p[0];
+
+ vga->sequencer[0x07] = 0x00;
+ if(mode->z == 8)
+ vga->sequencer[0x07] |= 0x01;
+
+ if(vga->f[0] >= 42000000)
+ vga->sequencer[0x0F] |= 0x20;
+ else
+ vga->sequencer[0x0F] &= ~0x20;
+
+ vga->sequencer[0x16] = (vga->sequencer[0x16] & 0xF0)|0x08;
+
+ /*
+ * Overflow bits.
+ */
+ vga->crt[0x1A] = 0x00;
+ x = mode->ehb>>3;
+ if(x & 0x40)
+ vga->crt[0x1A] |= 0x10;
+ if(x & 0x80)
+ vga->crt[0x1A] |= 0x20;
+ if(vga->crt[0x16] & 0x100)
+ vga->crt[0x1A] |= 0x40;
+ if(vga->crt[0x16] & 0x200)
+ vga->crt[0x1A] |= 0x80;
+ vga->crt[0x1B] = 0x22;
+ if(vga->crt[0x13] & 0x100)
+ vga->crt[0x1B] |= 0x10;
+
+ vga->graphics[0x0B] = 0x00;
+ if(vga->vmz > 1024*1024)
+ vga->graphics[0x0B] |= 0x20;
+
+ if(mode->interlace == 'v'){
+ vga->crt[0x19] = vga->crt[0x00]/2;
+ vga->crt[0x1A] |= 0x01;
+ }
+}
+
+static void
+load(Vga* vga, Ctlr* ctlr)
+{
+ vgaxo(Seqx, 0x0E, vga->sequencer[0x0E]);
+ vgaxo(Seqx, 0x1E, vga->sequencer[0x1E]);
+ if(ctlr->flag & Ulinear)
+ vga->sequencer[0x07] |= 0xE0;
+ vgaxo(Seqx, 0x07, vga->sequencer[0x07]);
+ vgaxo(Seqx, 0x0F, vga->sequencer[0x0F]);
+ vgaxo(Seqx, 0x16, vga->sequencer[0x16]);
+
+ if(vga->mode->interlace == 'v')
+ vgaxo(Crtx, 0x19, vga->crt[0x19]);
+ vgaxo(Crtx, 0x1A, vga->crt[0x1A]);
+ vgaxo(Crtx, 0x1B, vga->crt[0x1B]);
+
+ vgaxo(Grx, 0x0B, vga->graphics[0x0B]);
+}
+
+static void
+dump(Vga* vga, Ctlr* ctlr)
+{
+ int i;
+ char *name;
+
+ name = ctlr->name;
+
+ printitem(name, "Seq06");
+ for(i = 0x06; i < 0x20; i++)
+ printreg(vga->sequencer[i]);
+
+ printitem(name, "Crt19");
+ for(i = 0x19; i < 0x1E; i++)
+ printreg(vga->crt[i]);
+
+ printitem(name, "Gr09");
+ for(i = 0x09; i < 0x3A; i++)
+ printreg(vga->graphics[i]);
+
+ printitem(name, "Id Hdr");
+ printreg(vga->crt[0x27]);
+ printreg(vga->crt[0x28]);
+}
+
+Ctlr clgd542x = {
+ "clgd542x", /* name */
+ snarf, /* snarf */
+ 0, /* options */
+ init, /* init */
+ load, /* load */
+ dump, /* dump */
+};
+
+Ctlr clgd542xhwgc = {
+ "clgd542xhwgc", /* name */
+ 0, /* snarf */
+ 0, /* options */
+ 0, /* init */
+ 0, /* load */
+ 0, /* dump */
+};