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/clgd542x.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/vga/clgd542x.c')
-rwxr-xr-x | sys/src/cmd/aux/vga/clgd542x.c | 337 |
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 */ +}; |