xref: /plan9/sys/src/cmd/aux/vga/ics534x.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 
5 #include "pci.h"
6 #include "vga.h"
7 
8 /*
9  * ICS534x GENDAC.
10  * For now assumed to be hooked to either a Tseng Labs ET4000-W32p
11  * (Hercules Dynamite Power, the Hercules generates RS2 using CLK3)
12  * or an ARK2000pv (Diamond Stealth64 Graphics 2001).
13  */
14 static uchar
setrs2(Vga * vga,Ctlr * ctlr)15 setrs2(Vga* vga, Ctlr* ctlr)
16 {
17 	uchar rs2;
18 
19 	rs2 = 0;
20 	if(strncmp(vga->ctlr->name, "et4000-w32", 10) == 0){
21 		rs2 = vgaxi(Crtx, 0x31);
22 		vgaxo(Crtx, 0x31, 0x40|rs2);
23 	}
24 	else if(strncmp(vga->ctlr->name, "ark2000pv", 9) == 0){
25 		rs2 = vgaxi(Seqx, 0x1C);
26 		vgaxo(Seqx, 0x1C, 0x80|rs2);
27 	}
28 	else
29 		error("%s: not configured for %s\n", vga->ctlr->name, ctlr->name);
30 
31 	return rs2;
32 }
33 
34 static void
restorers2(Vga * vga,uchar rs2)35 restorers2(Vga* vga, uchar rs2)
36 {
37 	if(strncmp(vga->ctlr->name, "et4000-w32", 10) == 0)
38 		vgaxo(Crtx, 0x31, rs2);
39 	else if(strncmp(vga->ctlr->name, "ark2000pv", 9) == 0)
40 		vgaxo(Seqx, 0x1C, rs2);
41 }
42 
43 static void
options(Vga *,Ctlr * ctlr)44 options(Vga*, Ctlr* ctlr)
45 {
46 	ctlr->flag |= Hpclk2x8|Foptions;
47 }
48 
49 static void
clock(Vga * vga,Ctlr * ctlr)50 clock(Vga* vga, Ctlr* ctlr)
51 {
52 	ulong f, m, n, r;
53 	double fmin, fmax, t, tok;
54 
55 	/*
56 	 * The PLL frequency is defined by:
57 	 *		    (M+2)
58 	 *	 Fout = ------------ x Fref
59 	 *	        (N+2) x 2**R
60 	 * where M, N and R have the following contraints:
61 	 * 1)	     2MHz < Fref < 32MHz
62 	 * 2)		    Fref
63 	 *         600KHz < ----- <= 8Mhz
64 	 *	            (N+2)
65 	 * 3)		(M+2) x Fref
66 	 *     60MHz <= ------------ <= 270MHz
67 	 *		    (N+2)
68 	 * 4) Fout < 135MHz
69 	 * 5) 1 <= M <= 127, 1 <= N <= 31, 0 <= R <= 3
70 	 *
71 	 * First determine R by finding the highest value
72 	 * for which
73 	 *	      2**R x Fout <= 270Mhz
74 	 * The datasheet says that if the multiplexed 16-bit
75 	 * pseudo-colour mode is used then N2 (vga->r) must
76 	 * be 2.
77 	 */
78 	if(ctlr->flag & Upclk2x8)
79 		vga->r[0] = 2;
80 	else{
81 		vga->r[0] = 4;
82 		for(r = 0; r <= 3; r++){
83 			f = vga->f[0]*(1<<r);
84 			if(60000000 < f && f <= 270000000)
85 				vga->r[0] = r;
86 		}
87 		if(vga->r[0] > 3)
88 			error("%s: pclk %lud out of range\n",
89 				ctlr->name, vga->f[0]);
90 	}
91 
92 	/*
93 	 * Now find the closest match for M and N.
94 	 * Lower values of M and N give better noise rejection.
95 	 */
96 	fmin = vga->f[0]*0.995;
97 	fmax = vga->f[0]*1.005;
98 	tok = 0.0;
99 	for(n = 31; n >= 1; n--){
100 		t = RefFreq/(n+2);
101 		if(600000 >= t || t > 8000000)
102 			continue;
103 
104 		t = vga->f[0]*(n+2)*(1<<vga->r[0]);
105 		t /= RefFreq;
106 		m = (t+0.5) - 2;
107 		if(m > 127)
108 			continue;
109 
110 		t = (m+2)*RefFreq;
111 		t /= (n+2)*(1<<vga->r[0]);
112 
113 		if(fmin <= t && t < fmax){
114 			vga->m[0] = m;
115 			vga->n[0] = n;
116 			tok = t;
117 		}
118 	}
119 
120 	if(tok == 0.0)
121 		error("%s: pclk %lud out of range\n", ctlr->name, vga->f[0]);
122 }
123 
124 static void
init(Vga * vga,Ctlr * ctlr)125 init(Vga* vga, Ctlr* ctlr)
126 {
127 	ulong pclk;
128 	char *p;
129 
130 	/*
131 	 * Part comes in -135, -110 and -80MHz speed-grades.
132 	 */
133 	pclk = 80000000;
134 	if(p = strrchr(ctlr->name, '-'))
135 		pclk = strtoul(p+1, 0, 0) * 1000000;
136 
137 	/*
138 	 * If we don't already have a desired pclk,
139 	 * take it from the mode.
140 	 * Check it's within range.
141 	 */
142 	if(vga->f[0] == 0)
143 		vga->f[0] = vga->mode->frequency;
144 	if(vga->f[0] > pclk)
145 		error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]);
146 
147 	/*
148 	 * Determine whether to use 2x8-bit mode or not.
149 	 * If yes and the clock has already been initialised,
150 	 * initialise it again.
151 	 */
152 	if(vga->ctlr && (vga->ctlr->flag & Hpclk2x8) && vga->mode->z == 8 && vga->f[0] >= pclk/2){
153 		vga->f[0] /= 2;
154 		resyncinit(vga, ctlr, Upclk2x8, 0);
155 	}
156 
157 	/*
158 	 * Clock bits. If the desired video clock is
159 	 * one of the two standard VGA clocks it can just be
160 	 * set using bits <3:2> of vga->misc, otherwise we
161 	 * need to programme the DCLK PLL.
162 	 */
163 	vga->misc &= ~0x0C;
164 	if(vga->f[0] == VgaFreq0)
165 		vga->i[0] = 0;
166 	else if(vga->f[0] == VgaFreq1){
167 		vga->misc |= 0x04;
168 		vga->i[0] = 1;
169 	}
170 	else{
171 		/*
172 		 * Initialise the PLL parameters.
173 		 * Use CLK0 f7 internal clock (there are only 3
174 		 * clock-select bits).
175 		 */
176 		clock(vga, ctlr);
177 		vga->i[0] = 0x07;
178 	}
179 
180 	ctlr->flag |= Finit;
181 }
182 
183 static void
load(Vga * vga,Ctlr * ctlr)184 load(Vga* vga, Ctlr* ctlr)
185 {
186 	uchar rs2, mode, pll;
187 
188 	rs2 = setrs2(vga, ctlr);
189 
190 	/*
191 	 * Put the chip into snooze mode,
192 	 * colour mode 0.
193 	 */
194 	mode = 0x00;
195 	outportb(Pixmask, 0x01);
196 
197 	if(ctlr->flag & Upclk2x8)
198 		mode = 0x10;
199 
200 	/*
201 	 * If necessary, set the PLL parameters for CLK0 f7
202 	 * and make sure the PLL control register selects the
203 	 * correct clock. Preserve the memory clock setting.
204 	 */
205 	outportb(PaddrR, 0x0E);
206 	pll = inportb(Pdata) & 0x10;
207 	if(vga->i[0] == 0x07){
208 		outportb(PaddrW, vga->i[0]);
209 		outportb(Pdata, vga->m[0]);
210 		outportb(Pdata, (vga->r[0]<<5)|vga->n[0]);
211 		pll |= 0x27;
212 	}
213 	outportb(PaddrW, 0x0E);
214 	outportb(Pdata, pll);
215 	outportb(Pixmask, mode);
216 
217 	restorers2(vga, rs2);
218 	ctlr->flag |= Fload;
219 }
220 
221 static void
dump(Vga * vga,Ctlr * ctlr)222 dump(Vga* vga, Ctlr* ctlr)
223 {
224 	int i;
225 	uchar rs2, m, n;
226 	char buf[32];
227 	ulong f;
228 
229 	rs2 = setrs2(vga, ctlr);
230 
231 	printitem(ctlr->name, "command");
232 	printreg(inportb(Pixmask));
233 
234 	outportb(PaddrR, 0x00);
235 	for(i = 0; i < 0x0E; i++){
236 		sprint(buf, "f%X m n", i);
237 		printitem(ctlr->name, buf);
238 		m = inportb(Pdata);
239 		printreg(m);
240 		n = inportb(Pdata);
241 		printreg(n);
242 
243 		f = 14318180*(m+2);
244 		f /= (n & 0x1F)+2;
245 		f /= 1<<((n>>5) & 0x03);
246 		Bprint(&stdout, "%12lud", f);
247 	}
248 	printitem(ctlr->name, "control");
249 	printreg(inportb(Pdata));
250 
251 	restorers2(vga, rs2);
252 }
253 
254 Ctlr ics534x = {
255 	"ics534x",			/* name */
256 	0,				/* snarf */
257 	options,			/* options */
258 	init,				/* init */
259 	load,				/* load */
260 	dump,				/* dump */
261 };
262