ref: f4f19cdf1a8f0d2aa5f9fce10c896201528b5347
dir: /sys/src/cmd/aux/vga/tvp3020.c/
#include <u.h> #include <libc.h> #include <bio.h> #include "pci.h" #include "vga.h" /* * Tvp302[056] Viewpoint Video Interface Palette. * Assumes hooked up to an S3 86C928 or S3 Vision964. */ enum { Index = 0x06, /* Index register */ Data = 0x07, /* Data register */ Id = 0x3F, /* ID Register */ Tvp3020 = 0x20, Tvp3025 = 0x25, Tvp3026 = 0x26, }; /* * The following two arrays give read (bit 0) and write (bit 1) * permissions on the direct and index registers. Bits 4 and 5 * are for the Tvp3025. The Tvp3020 has only 8 direct registers. */ static uchar directreg[32] = { 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x11, 0x33, 0x33, 0x33, 0x33, 0x33, }; static uchar indexreg[64] = { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x02, 0x02, 0x33, 0x00, 0x00, 0x00, 0x30, 0x30, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x30, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x30, 0x30, 0x30, 0x30, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x30, 0x33, 0x11, 0x11, 0x11, 0x22, 0x11, }; /* * Check the index register access is valid. * Return the number of direct registers. */ static uchar checkindex(uchar index, uchar access) { uchar crt55; static uchar id; if(id == 0){ crt55 = vgaxi(Crtx, 0x55) & 0xFC; vgaxo(Crtx, 0x55, crt55|((Index>>2) & 0x03)); vgao(dacxreg[Index & 0x03], Id); id = vgai(dacxreg[Data & 0x03]); vgaxo(Crtx, 0x55, crt55); } if(index == 0xFF) return id; access &= 0x03; switch(id){ case Tvp3020: break; case Tvp3025: case Tvp3026: access = access<<4; break; default: Bprint(&stdout, "%s: unknown chip id - 0x%2.2X\n", tvp3020.name, id); break; } if(index > sizeof(indexreg) || (indexreg[index] & access) == 0) error("%s: bad register index - 0x%2.2X\n", tvp3020.name, index); return id; } static uchar tvp3020io(uchar reg, uchar data) { uchar crt55; crt55 = vgaxi(Crtx, 0x55) & 0xFC; vgaxo(Crtx, 0x55, crt55|((reg>>2) & 0x03)); vgao(dacxreg[reg & 0x03], data); return crt55; } uchar tvp3020i(uchar reg) { uchar crt55, r; crt55 = vgaxi(Crtx, 0x55) & 0xFC; vgaxo(Crtx, 0x55, crt55|((reg>>2) & 0x03)); r = vgai(dacxreg[reg & 0x03]); vgaxo(Crtx, 0x55, crt55); return r; } uchar tvp3020xi(uchar index) { uchar crt55, r; checkindex(index, 0x01); crt55 = tvp3020io(Index, index); r = vgai(dacxreg[Data & 0x03]); vgaxo(Crtx, 0x55, crt55); return r; } void tvp3020o(uchar reg, uchar data) { uchar crt55; crt55 = tvp3020io(reg, data); vgaxo(Crtx, 0x55, crt55); } void tvp3020xo(uchar index, uchar data) { uchar crt55; checkindex(index, 0x02); crt55 = tvp3020io(Index, index); vgao(dacxreg[Data & 0x03], data); vgaxo(Crtx, 0x55, crt55); } static void options(Vga*, Ctlr* ctlr) { ctlr->flag |= Hclk2|Hextsid|Hpvram|Henhanced|Foptions; } static void init(Vga* vga, Ctlr* ctlr) { ulong grade; char *p; /* * Work out the part speed-grade from name. Name can have, * e.g. '-135' on the end for 135MHz part. */ grade = 110000000; if(p = strrchr(ctlr->name, '-')) grade = strtoul(p+1, 0, 0) * 1000000; /* * If we don't already have a desired pclk, * take it from the mode. * Check it's within range. */ if(vga->f[0] == 0) vga->f[0] = vga->mode->frequency; if(vga->f[0] > grade) error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]); /* * Determine whether to use clock-doubler or not. */ if(vga->f[0] > 85000000){ vga->f[0] /= 2; resyncinit(vga, ctlr, Uclk2, 0); } ctlr->flag |= Finit; } static void load(Vga* vga, Ctlr* ctlr) { uchar x; /* * Input Clock Selection: * VGA CLK0 * enhanced CLK1 * doubled if necessary. */ x = 0x00; if(ctlr->flag & Uenhanced) x |= 0x01; if(ctlr->flag & Uclk2) x |= 0x10; tvp3020xo(0x1A, x); /* * Output Clock Selection: * VGA default VGA * enhanced RCLK=SCLK=/8, VCLK/4 */ x = 0x3E; if(ctlr->flag & Uenhanced) x = 0x53; tvp3020xo(0x1B, x); /* * Auxiliary Control: * default settings - self-clocked, palette graphics, no zoom * Colour Key Control: * default settings - pointing to palette graphics * Mux Control Register 1: * pseudo colour */ tvp3020xo(0x29, 0x09); tvp3020xo(0x38, 0x10); tvp3020xo(0x18, 0x80); /* * Mux Control Register 2: * VGA default VGA * enhanced 8-bpp, 8:1 mux, 64-bit pixel-bus width */ x = 0x98; if(ctlr->flag & Uenhanced){ if(vga->mode->z == 8) x = 0x1C; else if(vga->mode->z == 1) x = 0x04; } tvp3020xo(0x19, x); /* * General Control: * output sync polarity * It's important to set this properly and to turn off the * VGA controller H and V syncs. Can't be set in VGA mode. */ x = 0x00; if((vga->misc & 0x40) == 0) x |= 0x01; if((vga->misc & 0x80) == 0) x |= 0x02; tvp3020xo(0x1D, x); vga->misc |= 0xC0; vgao(MiscW, vga->misc); /* * Select the DAC via the General Purpose I/O * Register and Pins. * Guesswork by looking at register dumps. */ tvp3020xo(0x2A, 0x1F); if(ctlr->flag & Uenhanced) x = 0x1D; else x = 0x1C; tvp3020xo(0x2B, x); ctlr->flag |= Fload; } static void dump(Vga*, Ctlr* ctlr) { uchar access; int i; access = 0x01; if(checkindex(0x00, 0x01) != Tvp3020) access <<= 4; printitem(ctlr->name, "direct"); for(i = 0; i < 8; i++){ if(directreg[i] & access) printreg(tvp3020i(i)); else printreg(0xFF); } printitem(ctlr->name, "index"); for(i = 0; i < sizeof(indexreg); i++){ if(indexreg[i] & access) printreg(tvp3020xi(i)); else printreg(0xFF); } } Ctlr tvp3020 = { "tvp3020", /* name */ 0, /* snarf */ options, /* options */ init, /* init */ load, /* load */ dump, /* dump */ };