summaryrefslogtreecommitdiff
path: root/sys/src/cmd/aux/vga/ics534x.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/aux/vga/ics534x.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/vga/ics534x.c')
-rwxr-xr-xsys/src/cmd/aux/vga/ics534x.c261
1 files changed, 261 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/vga/ics534x.c b/sys/src/cmd/aux/vga/ics534x.c
new file mode 100755
index 000000000..a10554085
--- /dev/null
+++ b/sys/src/cmd/aux/vga/ics534x.c
@@ -0,0 +1,261 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+
+#include "pci.h"
+#include "vga.h"
+
+/*
+ * ICS534x GENDAC.
+ * For now assumed to be hooked to either a Tseng Labs ET4000-W32p
+ * (Hercules Dynamite Power, the Hercules generates RS2 using CLK3)
+ * or an ARK2000pv (Diamond Stealth64 Graphics 2001).
+ */
+static uchar
+setrs2(Vga* vga, Ctlr* ctlr)
+{
+ uchar rs2;
+
+ rs2 = 0;
+ if(strncmp(vga->ctlr->name, "et4000-w32", 10) == 0){
+ rs2 = vgaxi(Crtx, 0x31);
+ vgaxo(Crtx, 0x31, 0x40|rs2);
+ }
+ else if(strncmp(vga->ctlr->name, "ark2000pv", 9) == 0){
+ rs2 = vgaxi(Seqx, 0x1C);
+ vgaxo(Seqx, 0x1C, 0x80|rs2);
+ }
+ else
+ error("%s: not configured for %s\n", vga->ctlr->name, ctlr->name);
+
+ return rs2;
+}
+
+static void
+restorers2(Vga* vga, uchar rs2)
+{
+ if(strncmp(vga->ctlr->name, "et4000-w32", 10) == 0)
+ vgaxo(Crtx, 0x31, rs2);
+ else if(strncmp(vga->ctlr->name, "ark2000pv", 9) == 0)
+ vgaxo(Seqx, 0x1C, rs2);
+}
+
+static void
+options(Vga*, Ctlr* ctlr)
+{
+ ctlr->flag |= Hpclk2x8|Foptions;
+}
+
+static void
+clock(Vga* vga, Ctlr* ctlr)
+{
+ ulong f, m, n, r;
+ double fmin, fmax, t, tok;
+
+ /*
+ * The PLL frequency is defined by:
+ * (M+2)
+ * Fout = ------------ x Fref
+ * (N+2) x 2**R
+ * where M, N and R have the following contraints:
+ * 1) 2MHz < Fref < 32MHz
+ * 2) Fref
+ * 600KHz < ----- <= 8Mhz
+ * (N+2)
+ * 3) (M+2) x Fref
+ * 60MHz <= ------------ <= 270MHz
+ * (N+2)
+ * 4) Fout < 135MHz
+ * 5) 1 <= M <= 127, 1 <= N <= 31, 0 <= R <= 3
+ *
+ * First determine R by finding the highest value
+ * for which
+ * 2**R x Fout <= 270Mhz
+ * The datasheet says that if the multiplexed 16-bit
+ * pseudo-colour mode is used then N2 (vga->r) must
+ * be 2.
+ */
+ if(ctlr->flag & Upclk2x8)
+ vga->r[0] = 2;
+ else{
+ vga->r[0] = 4;
+ for(r = 0; r <= 3; r++){
+ f = vga->f[0]*(1<<r);
+ if(60000000 < f && f <= 270000000)
+ vga->r[0] = r;
+ }
+ if(vga->r[0] > 3)
+ error("%s: pclk %lud out of range\n",
+ ctlr->name, vga->f[0]);
+ }
+
+ /*
+ * Now find the closest match for M and N.
+ * Lower values of M and N give better noise rejection.
+ */
+ fmin = vga->f[0]*0.995;
+ fmax = vga->f[0]*1.005;
+ tok = 0.0;
+ for(n = 31; n >= 1; n--){
+ t = RefFreq/(n+2);
+ if(600000 >= t || t > 8000000)
+ continue;
+
+ t = vga->f[0]*(n+2)*(1<<vga->r[0]);
+ t /= RefFreq;
+ m = (t+0.5) - 2;
+ if(m > 127)
+ continue;
+
+ t = (m+2)*RefFreq;
+ t /= (n+2)*(1<<vga->r[0]);
+
+ if(fmin <= t && t < fmax){
+ vga->m[0] = m;
+ vga->n[0] = n;
+ tok = t;
+ }
+ }
+
+ if(tok == 0.0)
+ error("%s: pclk %lud out of range\n", ctlr->name, vga->f[0]);
+}
+
+static void
+init(Vga* vga, Ctlr* ctlr)
+{
+ ulong pclk;
+ char *p;
+
+ /*
+ * Part comes in -135, -110 and -80MHz speed-grades.
+ */
+ pclk = 80000000;
+ if(p = strrchr(ctlr->name, '-'))
+ pclk = 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] > pclk)
+ error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]);
+
+ /*
+ * Determine whether to use 2x8-bit mode or not.
+ * If yes and the clock has already been initialised,
+ * initialise it again.
+ */
+ if(vga->ctlr && (vga->ctlr->flag & Hpclk2x8) && vga->mode->z == 8 && vga->f[0] >= pclk/2){
+ vga->f[0] /= 2;
+ resyncinit(vga, ctlr, Upclk2x8, 0);
+ }
+
+ /*
+ * 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.
+ */
+ vga->misc &= ~0x0C;
+ if(vga->f[0] == VgaFreq0)
+ vga->i[0] = 0;
+ else if(vga->f[0] == VgaFreq1){
+ vga->misc |= 0x04;
+ vga->i[0] = 1;
+ }
+ else{
+ /*
+ * Initialise the PLL parameters.
+ * Use CLK0 f7 internal clock (there are only 3
+ * clock-select bits).
+ */
+ clock(vga, ctlr);
+ vga->i[0] = 0x07;
+ }
+
+ ctlr->flag |= Finit;
+}
+
+static void
+load(Vga* vga, Ctlr* ctlr)
+{
+ uchar rs2, mode, pll;
+
+ rs2 = setrs2(vga, ctlr);
+
+ /*
+ * Put the chip into snooze mode,
+ * colour mode 0.
+ */
+ mode = 0x00;
+ outportb(Pixmask, 0x01);
+
+ if(ctlr->flag & Upclk2x8)
+ mode = 0x10;
+
+ /*
+ * If necessary, set the PLL parameters for CLK0 f7
+ * and make sure the PLL control register selects the
+ * correct clock. Preserve the memory clock setting.
+ */
+ outportb(PaddrR, 0x0E);
+ pll = inportb(Pdata) & 0x10;
+ if(vga->i[0] == 0x07){
+ outportb(PaddrW, vga->i[0]);
+ outportb(Pdata, vga->m[0]);
+ outportb(Pdata, (vga->r[0]<<5)|vga->n[0]);
+ pll |= 0x27;
+ }
+ outportb(PaddrW, 0x0E);
+ outportb(Pdata, pll);
+ outportb(Pixmask, mode);
+
+ restorers2(vga, rs2);
+ ctlr->flag |= Fload;
+}
+
+static void
+dump(Vga* vga, Ctlr* ctlr)
+{
+ int i;
+ uchar rs2, m, n;
+ char buf[32];
+ ulong f;
+
+ rs2 = setrs2(vga, ctlr);
+
+ printitem(ctlr->name, "command");
+ printreg(inportb(Pixmask));
+
+ outportb(PaddrR, 0x00);
+ for(i = 0; i < 0x0E; i++){
+ sprint(buf, "f%X m n", i);
+ printitem(ctlr->name, buf);
+ m = inportb(Pdata);
+ printreg(m);
+ n = inportb(Pdata);
+ printreg(n);
+
+ f = 14318180*(m+2);
+ f /= (n & 0x1F)+2;
+ f /= 1<<((n>>5) & 0x03);
+ Bprint(&stdout, "%12lud", f);
+ }
+ printitem(ctlr->name, "control");
+ printreg(inportb(Pdata));
+
+ restorers2(vga, rs2);
+}
+
+Ctlr ics534x = {
+ "ics534x", /* name */
+ 0, /* snarf */
+ options, /* options */
+ init, /* init */
+ load, /* load */
+ dump, /* dump */
+};