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/s3clock.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/vga/s3clock.c')
-rwxr-xr-x | sys/src/cmd/aux/vga/s3clock.c | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/vga/s3clock.c b/sys/src/cmd/aux/vga/s3clock.c new file mode 100755 index 000000000..555bc84da --- /dev/null +++ b/sys/src/cmd/aux/vga/s3clock.c @@ -0,0 +1,278 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#include "pci.h" +#include "vga.h" + +/* + * Clocks which require fiddling with the S3 registers + * in order to be loaded. + */ +static void +setcrt42(Vga* vga, Ctlr* ctlr, uchar index) +{ + trace("%s->clock->setcrt42\n", ctlr->name); + + vgao(MiscW, vga->misc & ~0x0C); + outportb(Crtx+1, 0x00); + + vga->crt[0x42] = (vga->crt[0x42] & 0xF0)|index; + vgao(MiscW, vga->misc); + vgaxo(Crtx, 0x42, vga->crt[0x42]); +} + +static void +icd2061aload(Vga* vga, Ctlr* ctlr) +{ + ulong sdata; + int i; + uchar crt42; + + trace("%s->clock->icd2061aload\n", ctlr->name); + /* + * The serial word to be loaded into the icd2061a is + * (2<<21)|(vga->i<<17)|((vga->n)<<10)|(vga->p<<7)|vga->d + * Always select ICD2061A REG2. + */ + sdata = (2<<21)|(vga->i[0]<<17)|((vga->n[0])<<10)|(vga->p[0]<<7)|vga->d[0]; + + /* + * The display should be already off to enable us to clock the + * serial data word into either MiscW or Crt42. + * + * Set the Misc register to make clock-select-out the contents of + * register Crt42. Must turn the sequencer off when changing bits + * <3:2> of Misc. Also, must set Crt42 to 0 before setting <3:2> + * of Misc due to a hardware glitch. + */ + vgao(MiscW, vga->misc & ~0x0C); + crt42 = vgaxi(Crtx, 0x42) & 0xF0; + outportb(Crtx+1, 0x00); + + vgaxo(Seqx, 0x00, 0x00); + vgao(MiscW, vga->misc|0x0C); + vgaxo(Seqx, 0x00, 0x03); + + /* + * Unlock the ICD2061A. The unlock sequence is at least 5 low-to-high + * transitions of CLK with DATA high, followed by a single low-to-high + * transition of CLK with DATA low. + * Using Crt42, CLK is bit0, DATA is bit 1. If we used MiscW, they'd + * be bits 2 and 3 respectively. + */ + outportb(Crtx+1, crt42|0x00); /* -DATA|-CLK */ + outportb(Crtx+1, crt42|0x02); /* +DATA|-CLK */ + for(i = 0; i < 5; i++){ + outportb(Crtx+1, crt42|0x03); /* +DATA|+CLK */ + outportb(Crtx+1, crt42|0x02); /* +DATA|-CLK */ + } + outportb(Crtx+1, crt42|0x00); /* -DATA|-CLK */ + outportb(Crtx+1, crt42|0x01); /* -DATA|+CLK */ + + /* + * Now write the serial data word, framed by a start-bit and a stop-bit. + * The data is written using a modified Manchester encoding such that a + * data-bit is sampled on the rising edge of CLK and the complement of + * the data-bit is sampled on the previous falling edge of CLK. + */ + outportb(Crtx+1, crt42|0x00); /* -DATA|-CLK (start-bit) */ + outportb(Crtx+1, crt42|0x01); /* -DATA|+CLK */ + + for(i = 0; i < 24; i++){ /* serial data word */ + if(sdata & 0x01){ + outportb(Crtx+1, crt42|0x01); /* -DATA|+CLK */ + outportb(Crtx+1, crt42|0x00); /* -DATA|-CLK (falling edge) */ + outportb(Crtx+1, crt42|0x02); /* +DATA|-CLK */ + outportb(Crtx+1, crt42|0x03); /* +DATA|+CLK (rising edge) */ + } + else { + outportb(Crtx+1, crt42|0x03); /* +DATA|+CLK */ + outportb(Crtx+1, crt42|0x02); /* +DATA|-CLK (falling edge) */ + outportb(Crtx+1, crt42|0x00); /* -DATA|-CLK */ + outportb(Crtx+1, crt42|0x01); /* -DATA|+CLK (rising edge) */ + } + sdata >>= 1; + } + + outportb(Crtx+1, crt42|0x03); /* +DATA|+CLK (stop-bit) */ + outportb(Crtx+1, crt42|0x02); /* +DATA|-CLK */ + outportb(Crtx+1, crt42|0x03); /* +DATA|+CLK */ + + /* + * We always use REG2 in the ICD2061A. + */ + setcrt42(vga, ctlr, 0x02); +} + +static void +ch9294load(Vga* vga, Ctlr* ctlr) +{ + trace("%s->clock->ch9294load\n", ctlr->name); + + setcrt42(vga, ctlr, vga->i[0]); +} + +static void +tvp3025load(Vga* vga, Ctlr* ctlr) +{ + uchar crt5c, x; + + trace("%s->clock->tvp3025load\n", ctlr->name); + + /* + * Crt5C bit 5 is RS4. + * Clear it to select TVP3025 registers for + * the calls to tvp302xo(). + */ + crt5c = vgaxi(Crtx, 0x5C); + vgaxo(Crtx, 0x5C, crt5c & ~0x20); + + tvp3020xo(0x2C, 0x00); + tvp3020xo(0x2D, vga->d[0]); + tvp3020xo(0x2D, vga->n[0]); + tvp3020xo(0x2D, 0x08|vga->p[0]); + + tvp3020xo(0x2F, 0x01); + tvp3020xo(0x2F, 0x01); + tvp3020xo(0x2F, vga->p[0]); + x = 0x54; + if(vga->ctlr && (vga->ctlr->flag & Uenhanced)) + x = 0xC4; + tvp3020xo(0x1E, x); + + vgaxo(Crtx, 0x5C, crt5c); + vgao(MiscW, vga->misc); + + ctlr->flag |= Fload; +} + +static void +tvp3026load(Vga* vga, Ctlr* ctlr) +{ + trace("%s->clock->tvp3026load\n", ctlr->name); + + if((vga->misc & 0x0C) != 0x0C && vga->mode->z == 1){ + tvp3026xo(0x1A, 0x07); + tvp3026xo(0x18, 0x80); + tvp3026xo(0x19, 0x98); + tvp3026xo(0x2C, 0x2A); + tvp3026xo(0x2F, 0x00); + tvp3026xo(0x2D, 0x00); + tvp3026xo(0x39, 0x18); + setcrt42(vga, ctlr, 0); + } + else if(vga->mode->z == 8){ + tvp3026xo(0x1A, 0x05); + tvp3026xo(0x18, 0x80); + tvp3026xo(0x19, 0x4C); + tvp3026xo(0x2C, 0x2A); + tvp3026xo(0x2F, 0x00); + tvp3026xo(0x2D, 0x00); + + tvp3026xo(0x2C, 0x00); + tvp3026xo(0x2D, 0xC0|vga->n[0]); + tvp3026xo(0x2D, vga->m[0] & 0x3F); + tvp3026xo(0x2D, 0xB0|vga->p[0]); + while(!(tvp3026xi(0x2D) & 0x40)) + ; + + tvp3026xo(0x39, 0x38|vga->q[1]); + tvp3026xo(0x2C, 0x00); + tvp3026xo(0x2F, 0xC0|vga->n[1]); + tvp3026xo(0x2F, vga->m[1]); + tvp3026xo(0x2F, 0xF0|vga->p[1]); + while(!(tvp3026xi(0x2F) & 0x40)) + ; + + setcrt42(vga, ctlr, 3); + } + + ctlr->flag |= Fload; +} + +static struct { + char* name; + void (*load)(Vga*, Ctlr*); +} clocks[] = { + { "icd2061a", icd2061aload, }, + { "ch9294", ch9294load, }, + { "tvp3025clock", tvp3025load, }, + { "tvp3026clock", tvp3026load, }, + { 0 }, +}; + +static void +init(Vga* vga, Ctlr* ctlr) +{ + char name[Namelen+1], *p; + int i; + + if(vga->clock == 0) + return; + + /* + * Check we know about it. + */ + strncpy(name, vga->clock->name, Namelen); + name[Namelen] = 0; + if(p = strchr(name, '-')) + *p = 0; + for(i = 0; clocks[i].name; i++){ + if(strcmp(clocks[i].name, name) == 0) + break; + } + if(clocks[i].name == 0) + error("%s: unknown clock \"%s\"\n", ctlr->name, vga->clock->name); + + if(vga->clock->init && (vga->clock->flag & Finit) == 0) + (*vga->clock->init)(vga, vga->clock); + + /* + * If we don't already have a desired pclk, + * take it from the mode. + */ + if(vga->f[0] == 0) + vga->f[0] = vga->mode->frequency; + if(vga->f[0] != VgaFreq0 && vga->f[0] != VgaFreq1) + vga->misc |= 0x0C; + + ctlr->flag |= Finit; +} + +static void +load(Vga* vga, Ctlr* ctlr) +{ + char name[Namelen+1], *p; + int i; + + if(vga->clock == 0 || (vga->clock->flag & Fload)) + return; + + strncpy(name, vga->clock->name, Namelen); + name[Namelen] = 0; + if(p = strchr(name, '-')) + *p = 0; + + for(i = 0; clocks[i].name; i++){ + if(strcmp(clocks[i].name, name)) + continue; + clocks[i].load(vga, ctlr); + if(strcmp(clocks[i].name, "icd2061a") == 0){ + clocks[i].load(vga, ctlr); + clocks[i].load(vga, ctlr); + } + + ctlr->flag |= Fload; + return; + } +} + +Ctlr s3clock = { + "s3clock", /* name */ + 0, /* snarf */ + 0, /* options */ + init, /* init */ + load, /* load */ + 0, /* dump */ +}; |