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/3dfx.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/vga/3dfx.c')
-rwxr-xr-x | sys/src/cmd/aux/vga/3dfx.c | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/vga/3dfx.c b/sys/src/cmd/aux/vga/3dfx.c new file mode 100755 index 000000000..e42b7c9c0 --- /dev/null +++ b/sys/src/cmd/aux/vga/3dfx.c @@ -0,0 +1,348 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#include "pci.h" +#include "vga.h" + +/* + * 3Dfx. + */ +enum { + dramInit0 = 0x018/4, + dramInit1 = 0x01C/4, + vgaInit0 = 0x028/4, + pllCtrl0 = 0x040/4, + pllCtrl1 = 0x044/4, + pllCtrl2 = 0x048/4, + dacMode = 0x04C/4, + vidProcCfg = 0x05C/4, + vidScreenSize = 0x098/4, + vidDesktopOverlayStride = 0x0E8/4, + + Nior = 0x100/4, +}; + +typedef struct Tdfx { + ulong io; + Pcidev* pci; + + ulong r[Nior]; +} Tdfx; + +static ulong +io32r(Tdfx* tdfx, int r) +{ + return inportl(tdfx->io+(r*4)); +} + +static void +io32w(Tdfx* tdfx, int r, ulong l) +{ + outportl(tdfx->io+(r*4), l); +} + +static void +snarf(Vga* vga, Ctlr* ctlr) +{ + int i; + ulong v; + Tdfx *tdfx; + + if(vga->private == nil){ + tdfx = alloc(sizeof(Tdfx)); + tdfx->pci = pcimatch(0, 0x121A, 0); + if(tdfx->pci == nil) + error("%s: not found\n", ctlr->name); + switch(tdfx->pci->did){ + default: + error("%s: unknown chip - DID %4.4uX\n", + ctlr->name, tdfx->pci->did); + break; + case 0x0003: /* Banshee */ + vga->f[1] = 270000000; + break; + case 0x0005: /* Avenger (a.k.a. Voodoo3) */ + vga->f[1] = 300000000; + break; + case 0x0009: /* Voodoo5 */ + vga->f[1] = 350000000; + break; + } + /* + * Frequency output of PLL's is given by + * fout = RefFreq*(n+2)/((m+2)*2^p) + * where there are 6 bits for m, 8 bits for n + * and 2 bits for p (k). + */ + vga->m[1] = 64; + vga->n[1] = 256; + vga->p[1] = 4; + + if((v = (tdfx->pci->mem[2].bar & ~0x3)) == 0) + error("%s: I/O not mapped\n", ctlr->name); + tdfx->io = v; + + vga->private = tdfx; + } + tdfx = vga->private; + + vga->crt[0x1A] = vgaxi(Crtx, 0x1A); + vga->crt[0x1B] = vgaxi(Crtx, 0x1B); + for(i = 0; i < Nior; i++) + tdfx->r[i] = io32r(tdfx, i); + + /* + * If SDRAM then there's 16MB memory else it's SGRAM + * and can count it based on the power-on straps - + * chip size can be 8Mb or 16Mb, and there can be 4 or + * 8 of them. + */ + vga->vma = tdfx->pci->mem[1].size; + if(tdfx->r[dramInit1] & 0x40000000) + vga->vmz = 16*1024*1024; + else{ + if(tdfx->r[dramInit0] & 0x08000000) + i = 16*1024*1024/8; + else + i = 8*1024*1024/8; + if(tdfx->r[dramInit0] & 0x04000000) + i *= 8; + else + i *= 4; + vga->vmz = i; + } + + ctlr->flag |= Fsnarf; +} + +static void +options(Vga*, Ctlr* ctlr) +{ + ctlr->flag |= Hlinear|Hclk2|Foptions; +} + +static void +tdfxclock(Vga* vga, Ctlr*) +{ + int d, dmin; + uint f, m, n, p; + + dmin = vga->f[0]; + for(m = 1; m < vga->m[1]; m++){ + for(n = 1; n < vga->n[1]; n++){ + f = (RefFreq*(n+2))/(m+2); + for(p = 0; p < vga->p[1]; p++){ + d = vga->f[0] - (f/(1<<p)); + if(d < 0) + d = -d; + if(d >= dmin) + continue; + dmin = d; + vga->m[0] = m; + vga->n[0] = n; + vga->p[0] = p; + } + } + } +} + +static void +init(Vga* vga, Ctlr* ctlr) +{ + int x; + Mode *mode; + Tdfx *tdfx; + + mode = vga->mode; + tdfx = vga->private; + + if(vga->linear && (ctlr->flag & Hlinear)) + ctlr->flag |= Ulinear; + + /* + * Clock bits. If the desired video clock is + * one of the two standard VGA clocks or 50MHz it can just be + * set using bits <3:2> of vga->misc, otherwise we + * need to programme the PLL. + */ + if(vga->f[0] == 0) + vga->f[0] = mode->frequency; + vga->misc &= ~0x0C; + if(vga->f[0] == VgaFreq0){ + /* nothing to do */; + } + else if(vga->f[0] == VgaFreq1) + vga->misc |= 0x04; + else if(vga->f[0] == 50000000) + vga->misc |= 0x08; + else{ + if(vga->f[0] > vga->f[1]) + error("%s: invalid pclk - %lud\n", + ctlr->name, vga->f[0]); + if(vga->f[0] > 135000000 && (ctlr->flag & Hclk2)){ + if(mode->x%16) + error("%s: f > 135MHz requires (x%%16) == 0\n", + ctlr->name); + ctlr->flag |= Uclk2; + } + tdfxclock(vga, ctlr); + + tdfx->r[pllCtrl0] = (vga->n[0]<<8)|(vga->m[0]<<2)|vga->p[0]; + vga->misc |= 0x0C; + } + + /* + * Pixel format and memory stride. + */ + tdfx->r[vidScreenSize] = (mode->y<<12)|mode->x; + tdfx->r[vidProcCfg] = 0x00000081; + switch(mode->z){ + default: + error("%s: %d-bit mode not supported\n", ctlr->name, mode->z); + break; + case 8: + tdfx->r[vidDesktopOverlayStride] = mode->x; + break; + case 16: + tdfx->r[vidDesktopOverlayStride] = mode->x*2; + tdfx->r[vidProcCfg] |= 0x00040400; + break; + case 32: + tdfx->r[vidDesktopOverlayStride] = mode->x*4; + tdfx->r[vidProcCfg] |= 0x000C0400; + break; + } + tdfx->r[vgaInit0] = 0x140; + + /* + * Adjust horizontal timing if doing two screen pixels per clock. + */ + tdfx->r[dacMode] = 0; + if(ctlr->flag & Uclk2){ + vga->crt[0x00] = ((mode->ht/2)>>3)-5; + vga->crt[0x01] = ((mode->x/2)>>3)-1; + vga->crt[0x02] = ((mode->shb/2)>>3)-1; + + x = (mode->ehb/2)>>3; + vga->crt[0x03] = 0x80|(x & 0x1F); + vga->crt[0x04] = (mode->shs/2)>>3; + vga->crt[0x05] = ((mode->ehs/2)>>3) & 0x1F; + if(x & 0x20) + vga->crt[0x05] |= 0x80; + + tdfx->r[dacMode] |= 0x01; + tdfx->r[vidProcCfg] |= 0x04000000; + } + + /* + * Overflow. + */ + vga->crt[0x1A] = 0x00; + if(vga->crt[0x00] & 0x100) + vga->crt[0x1A] |= 0x01; + if(vga->crt[0x01] & 0x100) + vga->crt[0x1A] |= 0x04; + if(vga->crt[0x03] & 0x100) + vga->crt[0x1A] |= 0x10; + x = mode->ehb; + if(ctlr->flag & Uclk2) + x /= 2; + if((x>>3) & 0x40) + vga->crt[0x1A] |= 0x20; + if(vga->crt[0x04] & 0x100) + vga->crt[0x1A] |= 0x40; + x = mode->ehs; + if(ctlr->flag & Uclk2) + x /= 2; + if((x>>3) & 0x20) + vga->crt[0x1A] |= 0x80; + + vga->crt[0x1B] = 0x00; + if(vga->crt[0x06] & 0x400) + vga->crt[0x1B] |= 0x01; + if(vga->crt[0x12] & 0x400) + vga->crt[0x1B] |= 0x04; + if(vga->crt[0x15] & 0x400) + vga->crt[0x1B] |= 0x10; + if(vga->crt[0x10] & 0x400) + vga->crt[0x1B] |= 0x40; + + vga->attribute[0x11] = Pblack; + + ctlr->flag |= Finit; +} + +static void +load(Vga* vga, Ctlr* ctlr) +{ + Tdfx *tdfx; + + vgaxo(Crtx, 0x1A, vga->crt[0x1A]); + vgaxo(Crtx, 0x1B, vga->crt[0x1B]); + + tdfx = vga->private; + io32w(tdfx, dacMode, tdfx->r[dacMode]); + io32w(tdfx, vidScreenSize, tdfx->r[vidScreenSize]); + io32w(tdfx, vidDesktopOverlayStride, tdfx->r[vidDesktopOverlayStride]); + io32w(tdfx, vidProcCfg, tdfx->r[vidProcCfg]); + io32w(tdfx, vgaInit0, tdfx->r[vgaInit0]); + + if((vga->misc & 0x0C) == 0x0C) + io32w(tdfx, pllCtrl0, tdfx->r[pllCtrl0]); + + ctlr->flag |= Fload; +} + +static uint +pllctrl(Tdfx* tdfx, int pll) +{ + uint k, m, n, r; + + r = tdfx->r[pllCtrl0+pll]; + k = r & 0x03; + m = (r>>2) & 0x3F; + n = (r>>8) & 0xFF; + + return (RefFreq*(n+2))/((m+2)*(1<<k)); +} + +static void +dump(Vga* vga, Ctlr* ctlr) +{ + int i; + Tdfx *tdfx; + + if((tdfx = vga->private) == nil) + return; + + printitem(ctlr->name, "Crt1A"); + printreg(vga->crt[0x1A]); + printreg(vga->crt[0x1B]); + + Bprint(&stdout, "\n"); + for(i = 0; i < Nior; i++) + Bprint(&stdout, "%s %2.2uX\t%.8luX\n", + ctlr->name, i*4, tdfx->r[i]); + + printitem(ctlr->name, "pllCtrl"); + Bprint(&stdout, "%9ud %8ud\n", pllctrl(tdfx, 0), pllctrl(tdfx, 1)); +} + +Ctlr tdfx = { + "3dfx", /* name */ + snarf, /* snarf */ + options, /* options */ + init, /* init */ + load, /* load */ + dump, /* dump */ +}; + +Ctlr tdfxhwgc = { + "3dfxhwgc", /* name */ + 0, /* snarf */ + 0, /* options */ + 0, /* init */ + 0, /* load */ + 0, /* dump */ +}; |