123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- #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 */
- };
|