123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include "pci.h"
- #include "vga.h"
- /*
- * S3 Trio64.
- */
- static void
- snarf(Vga* vga, Ctlr* ctlr)
- {
- int i;
- /*
- * The Trio has some extra sequencer registers which
- * need to be unlocked for access.
- */
- vgaxo(Seqx, 0x08, 0x06);
- for(i = 0x08; i < 0x19; i++)
- vga->sequencer[i] = vgaxi(Seqx, i);
- vga->crt[0x2D] = vgaxi(Crtx, 0x2D);
- vga->crt[0x2E] = vgaxi(Crtx, 0x2E);
- vga->crt[0x2F] = vgaxi(Crtx, 0x2F);
- s3generic.snarf(vga, ctlr);
- ctlr->flag |= Fsnarf;
- }
- static void
- options(Vga*, Ctlr* ctlr)
- {
- ctlr->flag |= Hlinear|Hpclk2x8|Henhanced|Foptions;
- }
- void
- trio64clock(Vga* vga, Ctlr* ctlr)
- {
- int d;
- ulong f, fmax, fmin, n, m, r;
- double trouble;
- /*
- * The max value of R, M, N, and the speed rating of the part vary
- * between parts and are passed to this routine in r[1] and f[1].
- * R F
- * Trio64 3 135000000
- * ViRGE 3 135000000
- * ViRGE/[DG]X 4 170000000
- * ViRGE/GX2 4 170000000
- * ViRGE/VX 4 220000000
- */
- /*
- * The PLL frequency is defined by the following equation:
- * (M+2)
- * Fout = ------------- x Fref
- * (N+2) x 2**R
- * where M, N and R have the following contraints:
- * 1) (M+2) x Fref
- * vga->f[1] <= ------------ <= vga->f[1]*2
- * (N+2)
- * 2) 1 <= M <= vga->m[1] (usually 127)
- * 3) 1 <= N <= vga->n[1] (usually 31)
- * 4) 0 <= R <= vga->r[1]
- *
- * First determine R:
- * vga->f[1] < 2**R x Fout <= vga->f[1]*2
- */
- for(r = 0; r <= vga->r[1]; r++){
- f = vga->f[0]*(1<<r);
- if(vga->f[1] < f && f <= vga->f[1]*2)
- vga->r[0] = r;
- }
- if(vga->r[0] > vga->r[1])
- error("%s: pclk %lud out of range\n", ctlr->name, vga->f[0]);
- /*
- * Now find the closest match for M and N.
- */
- vga->d[0] = vga->f[0]+1;
- for(n = 1; n <= vga->n[1]; n++){
- trouble = vga->f[0]*(n+2)*(1<<vga->r[0]);
- trouble /= RefFreq;
- m = (trouble+0.5) - 2;
- if(m > vga->m[1])
- continue;
- trouble = (m+2)*RefFreq;
- trouble /= (n+2)*(1<<vga->r[0]);
- f = trouble+0.5;
- d = vga->f[0] - f;
- if(d < 0)
- d = -d;
- if(d <= vga->d[0]){
- vga->m[0] = m;
- vga->n[0] = n;
- vga->d[0] = d;
- }
- }
- trouble = vga->f[0]*1.005;
- fmax = trouble;
- trouble = vga->f[0]*0.995;
- fmin = trouble;
- trouble = (vga->m[0]+2)*RefFreq;
- trouble /= (vga->n[0]+2)*(1<<vga->r[0]);
- f = trouble+0.5;
- if(fmin >= f || f >= fmax)
- error("%s: pclk %lud out of range\n", ctlr->name, vga->f[0]);
- }
- static void
- init(Vga* vga, Ctlr* ctlr)
- {
- ulong pclk, x;
- s3generic.init(vga, ctlr);
- /*
- * Clock bits. If the desired video clock is
- * one of the two standard VGA clocks it can just be
- * set using bits <3:2> of vga->misc, otherwise we
- * need to programme the DCLK PLL.
- */
- if(vga->mode->z > 8)
- error("depth %d not supported\n", vga->mode->z);
- if(vga->f[0] == 0)
- vga->f[0] = vga->mode->frequency;
- vga->misc &= ~0x0C;
- if(vga->f[0] == VgaFreq0){
- /* nothing to do */;
- }
- else if(vga->f[0] == VgaFreq1)
- vga->misc |= 0x04;
- else{
- /*
- * Part comes in -135MHz speed grade. In 8-bit mode
- * the maximum DCLK is 80MHz. In 2x8-bit mode the maximum
- * DCLK is 135MHz using the internal clock doubler.
- */
- if((ctlr->flag & Hpclk2x8) && vga->mode->z == 8){
- pclk = 135000000;
- if(vga->f[0] > 80000000)
- ctlr->flag |= Upclk2x8;
- }
- else
- pclk = 80000000;
- if(vga->f[0] > pclk)
- error("%s: invalid pclk - %lud\n",
- ctlr->name, vga->f[0]);
- vga->f[1] = 135000000;
- vga->r[1] = 3;
- vga->n[1] = 31;
- vga->m[1] = 127;
- trio64clock(vga, ctlr);
- vga->sequencer[0x12] = (vga->r[0]<<5)|vga->n[0];
- vga->sequencer[0x13] = vga->m[0];
- vga->misc |= 0x0C;
- }
- /*
- * Internal clock generator.
- */
- vga->sequencer[0x15] &= ~0x31;
- vga->sequencer[0x15] |= 0x02;
- vga->sequencer[0x18] &= ~0x80;
- vga->crt[0x67] &= ~0xF2;
- if(ctlr->flag & Upclk2x8){
- vga->sequencer[0x15] |= 0x10;
- vga->sequencer[0x18] |= 0x80;
- /*
- * There's a little strip of the border
- * appears on the left in resolutions
- * 1280 and above if the 0x02 bit isn't
- * set (when it appears on the right...).
- */
- vga->crt[0x67] |= 0x10;
- }
- /*
- * VLB address latch delay.
- */
- if((vga->crt[0x36] & 0x03) == 0x01)
- vga->crt[0x58] &= ~0x08;
- /*
- * Start display FIFO fetch.
- */
- x = vga->crt[0]-5;
- vga->crt[0x3B] = x;
- if(x & 0x100)
- vga->crt[0x5D] |= 0x40;
- /*
- * Display memory access control.
- * Calculation of the M-parameter (Crt54) is
- * memory-system and dot-clock dependent, the
- * values below are guesses from dumping
- * registers.
- */
- vga->crt[0x60] = 0xFF;
- if(vga->mode->x <= 800)
- vga->crt[0x54] = 0xE8;
- else if(vga->mode->x <= 1024)
- vga->crt[0x54] = 0xA8;
- else
- vga->crt[0x54] = 0x00/*0x48*/;
- ctlr->flag |= Finit;
- }
- static void
- load(Vga* vga, Ctlr* ctlr)
- {
- ushort advfunc;
- s3generic.load(vga, ctlr);
- vgaxo(Crtx, 0x60, vga->crt[0x60]);
- vgaxo(Crtx, 0x67, vga->crt[0x67]);
- /*
- * Load the PLL registers if necessary.
- * Not sure if the variable-delay method of setting the
- * PLL will work without a write here to vga->misc,
- * so use the immediate-load method by toggling bit 5
- * of Seq15 if necessary.
- */
- vgaxo(Seqx, 0x12, vga->sequencer[0x12]);
- vgaxo(Seqx, 0x13, vga->sequencer[0x13]);
- if((vga->misc & 0x0C) == 0x0C)
- vgaxo(Seqx, 0x15, vga->sequencer[0x15]|0x20);
- vgaxo(Seqx, 0x15, vga->sequencer[0x15]);
- vgaxo(Seqx, 0x18, vga->sequencer[0x18]);
- advfunc = 0x0000;
- if(ctlr->flag & Uenhanced)
- advfunc = 0x0001;
- outportw(0x4AE8, advfunc);
- }
- static void
- dump(Vga* vga, Ctlr* ctlr)
- {
- int i;
- ulong dclk, m, n, r;
- s3generic.dump(vga, ctlr);
- printitem(ctlr->name, "Seq08");
- for(i = 0x08; i < 0x19; i++)
- printreg(vga->sequencer[i]);
- printitem(ctlr->name, "Crt2D");
- printreg(vga->crt[0x2D]);
- printreg(vga->crt[0x2E]);
- printreg(vga->crt[0x2F]);
- n = vga->sequencer[0x12] & 0x1F;
- r = (vga->sequencer[0x12]>>5) & 0x03;
- m = vga->sequencer[0x13] & 0x7F;
- dclk = (m+2)*RefFreq;
- dclk /= (n+2)*(1<<r);
- printitem(ctlr->name, "dclk m n r");
- Bprint(&stdout, "%9ld %8ld - %8ld %8ld\n", dclk, m, n, r);
- }
- Ctlr trio64 = {
- "trio64", /* name */
- snarf, /* snarf */
- options, /* options */
- init, /* init */
- load, /* load */
- dump, /* dump */
- };
|