xref: /plan9/sys/src/cmd/aux/vga/rgb524.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  * IBM RGB524.
10  * 170/220MHz High Performance Palette DAC.
11  *
12  * Assumes hooked up to an S3 Vision96[48].
13  */
14 enum {
15 	IndexLo		= 0x00,
16 	IndexHi		= 0x01,
17 	Data		= 0x02,
18 	IndexCtl	= 0x03,
19 };
20 
21 enum {						/* index registers */
22 	MiscClock	= 0x02,
23 	PixelFormat	= 0x0A,
24 	PLLControl1	= 0x10,
25 	PLLControl2	= 0x11,
26 	PLLReference	= 0x14,
27 	Frequency0	= 0x20,
28 	MiscControl1	= 0x70,
29 	MiscControl2	= 0x71,
30 };
31 
32 static uchar
setrs2(void)33 setrs2(void)
34 {
35 	uchar rs2;
36 
37 	rs2 = vgaxi(Crtx, 0x55);
38 	vgaxo(Crtx, 0x55, (rs2 & 0xFC)|0x01);
39 
40 	return rs2;
41 }
42 
43 static uchar
rgb524xi(int index)44 rgb524xi(int index)
45 {
46 	outportb(dacxreg[IndexLo], index & 0xFF);
47 	outportb(dacxreg[IndexHi], (index>>8) & 0xFF);
48 
49 	return inportb(dacxreg[Data]);
50 }
51 
52 static void
rgb524xo(int index,uchar data)53 rgb524xo(int index, uchar data)
54 {
55 	outportb(dacxreg[IndexLo], index & 0xFF);
56 	outportb(dacxreg[IndexHi], (index>>8) & 0xFF);
57 
58 	outportb(dacxreg[Data], data);
59 }
60 
61 static void
restorers2(uchar rs2)62 restorers2(uchar rs2)
63 {
64 	vgaxo(Crtx, 0x55, rs2);
65 }
66 
67 static void
clock(Vga * vga,Ctlr * ctlr)68 clock(Vga* vga, Ctlr* ctlr)
69 {
70 	if(vga->f[0] >= 16250000 && vga->f[0] <= 32000000){
71 		vga->f[0] = (vga->f[0]/250000)*250000;
72 		vga->d[0] = (4*vga->f[0])/1000000 - 65;
73 	}
74 	else if(vga->f[0] >= 32500000 && vga->f[0] <= 64000000){
75 		vga->f[0] = (vga->f[0]/500000)*500000;
76 		vga->d[0] = 0x40|((2*vga->f[0])/1000000 - 65);
77 	}
78 	else if(vga->f[0] >= 65000000 && vga->f[0] <= 128000000){
79 		vga->f[0] = (vga->f[0]/1000000)*1000000;
80 		vga->d[0] = 0x80|(vga->f[0]/1000000 - 65);
81 	}
82 	else if(vga->f[0] >= 130000000 && vga->f[0] <= 220000000){
83 		vga->f[0] = (vga->f[0]/2000000)*2000000;
84 		vga->d[0] = 0xC0|((vga->f[0]/2)/1000000 - 65);
85 	}
86 	else
87 		error("%s: pclk %lud out of range\n",
88 			ctlr->name, vga->f[0]);
89 }
90 
91 static void
init(Vga * vga,Ctlr * ctlr)92 init(Vga* vga, Ctlr* ctlr)
93 {
94 	ulong pclk;
95 	char *p;
96 
97 	/*
98 	 * Part comes in -170 and -220MHz speed-grades.
99 	 */
100 	pclk = 170000000;
101 	if(p = strrchr(ctlr->name, '-'))
102 		pclk = strtoul(p+1, 0, 0) * 1000000;
103 
104 	/*
105 	 * If we don't already have a desired pclk,
106 	 * take it from the mode.
107 	 * Check it's within range.
108 	 */
109 	if(vga->f[0] == 0)
110 		vga->f[0] = vga->mode->frequency;
111 	if(vga->f[0] > pclk)
112 		error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]);
113 
114 	/*
115 	 * Determine whether to use clock-doubler or not.
116 	 */
117 	if((ctlr->flag & Uclk2) == 0 && vga->mode->z == 8)
118 		resyncinit(vga, ctlr, Uclk2, 0);
119 
120 	/*
121 	 * Clock bits. If the desired video clock is
122 	 * one of the two standard VGA clocks it can just be
123 	 * set using bits <3:2> of vga->misc, otherwise we
124 	 * need to programme the PLL.
125 	 */
126 	vga->misc &= ~0x0C;
127 	if(vga->mode->z == 8 || (vga->f[0] != VgaFreq0 && vga->f[0] != VgaFreq1)){
128 		/*
129 		 * Initialise the PLL parameters.
130 		 * Use internal FS3 fixed-reference divider.
131 		 */
132 		clock(vga, ctlr);
133 		vga->i[0] = 0x03;
134 	}
135 	else if(vga->f[0] == VgaFreq0)
136 		vga->i[0] = 0;
137 	else if(vga->f[0] == VgaFreq1){
138 		vga->misc |= 0x04;
139 		vga->i[0] = 1;
140 	}
141 
142 	ctlr->flag |= Finit;
143 }
144 
145 static void
load(Vga * vga,Ctlr * ctlr)146 load(Vga* vga, Ctlr* ctlr)
147 {
148 	uchar mc2, rs2, x;
149 	char *val;
150 	int f;
151 
152 	rs2 = setrs2();
153 
154 	/*
155 	 * Set VgaFreq[01].
156 	 */
157 	rgb524xo(PLLControl1, 0x00);
158 	rgb524xo(Frequency0, 0x24);
159 	rgb524xo(Frequency0+1, 0x30);
160 
161 	if(val = dbattr(vga->attr, "rgb524refclk")){
162 		f = strtol(val, 0, 0);
163 		if(f > 1000000)
164 			f /= 1000000;
165 		rgb524xo(PLLReference, f/2);
166 	}
167 
168 	/*
169 	 * Enable pixel programming and clock divide
170 	 * factor.
171 	 */
172 	x = rgb524xi(MiscClock) & ~0x0E;
173 	x |= 0x01;
174 	if(ctlr->flag & Uclk2)
175 		x |= 0x02;
176 	rgb524xo(MiscClock, x);
177 
178 	if(vga->mode->z == 1)
179 		rgb524xo(PixelFormat, 0x02);
180 	else if(vga->mode->z == 8)
181 		rgb524xo(PixelFormat, 0x03);
182 
183 	x = rgb524xi(MiscControl1) & ~0x41;
184 	x |= 0x01;
185 	rgb524xo(MiscControl1, x);
186 
187 	mc2 = rgb524xi(MiscControl2) & ~0x41;
188 	vga->crt[0x22] &= ~0x08;
189 	if(vga->i[0] == 3){
190 		rgb524xo(Frequency0+3, vga->d[0]);
191 		rgb524xo(PLLControl1, 0x02);
192 		rgb524xo(PLLControl2, vga->i[0]);
193 		mc2 |= 0x41;
194 		vga->crt[0x22] |= 0x08;
195 	}
196 	rgb524xo(MiscControl2, mc2);
197 	vgaxo(Crtx, 0x22, vga->crt[0x22]);
198 
199 	restorers2(rs2);
200 	ctlr->flag |= Fload;
201 }
202 
203 static void
dump(Vga *,Ctlr * ctlr)204 dump(Vga*, Ctlr* ctlr)
205 {
206 	uchar rs2, r, x[256];
207 	char buf[32];
208 	int df, i, maxf, vcodc, vf;
209 
210 	rs2 = setrs2();
211 	printitem(ctlr->name, "index00");
212 	for(i = 0x00; i < 0x0F; i++){
213 		x[i] = rgb524xi(i);
214 		printreg(x[i]);
215 	}
216 	printitem(ctlr->name, "index10");
217 	for(i = 0x10; i < 0x17; i++){
218 		x[i] = rgb524xi(i);
219 		printreg(x[i]);
220 	}
221 	printitem(ctlr->name, "index20");
222 	for(i = 0x20; i < 0x30; i++){
223 		x[i] = rgb524xi(i);
224 		printreg(x[i]);
225 	}
226 	printitem(ctlr->name, "index30");
227 	for(i = 0x30; i < 0x37; i++){
228 		x[i] = rgb524xi(i);
229 		printreg(x[i]);
230 	}
231 	printitem(ctlr->name, "index40");
232 	for(i = 0x40; i < 0x49; i++){
233 		x[i] = rgb524xi(i);
234 		printreg(x[i]);
235 	}
236 	printitem(ctlr->name, "index60");
237 	for(i = 0x60; i < 0x63; i++){
238 		x[i] = rgb524xi(i);
239 		printreg(x[i]);
240 	}
241 	printitem(ctlr->name, "index70");
242 	for(i = 0x70; i < 0x73; i++){
243 		x[i] = rgb524xi(i);
244 		printreg(x[i]);
245 	}
246 	printitem(ctlr->name, "index8E");
247 	for(i = 0x8E; i < 0x92; i++){
248 		x[i] = rgb524xi(i);
249 		printreg(x[i]);
250 	}
251 	restorers2(rs2);
252 
253 	/*
254 	 * x[0x10]	pixel clock frequency selection
255 	 *		0, 2 for direct programming
256 	 * x[0x20-0x2F]	pixel frequency 0-15
257 	 */
258 	printitem(ctlr->name, "refclk");
259 	Bprint(&stdout, "%12ud\n", x[PLLReference]*2*1000000);
260 	if((i = (x[0x10] & 0x07)) == 0x00 || i == 0x02){
261 		/*
262 		 * Direct programming, external frequency select.
263 		 * F[0-4] are probably tied directly to the 2 clock-select
264 		 * bits in the VGA Misc register.
265 		 */
266 		if(i == 0)
267 			maxf = 4;
268 		else
269 			maxf = 16;
270 		for(i = 0; i < maxf; i++){
271 			if((r = x[0x20+i]) == 0)
272 				continue;
273 			sprint(buf, "direct F%X", i);
274 			printitem(ctlr->name, buf);
275 			df = (r>>6) & 0x03;
276 			vcodc = r & 0x3F;
277 
278 			vf = 0;
279 			switch(df){
280 			case 0:
281 				vf = (vcodc+65)/4;
282 				break;
283 
284 			case 1:
285 				vf = (vcodc+65)/2;
286 				break;
287 
288 			case 2:
289 				vf = (vcodc+65);
290 				break;
291 
292 			case 3:
293 				vf = (vcodc+65)*2;
294 				break;
295 			}
296 			Bprint(&stdout, "%12ud\n", vf);
297 		}
298 	}
299 }
300 
301 Ctlr rgb524 = {
302 	"rgb524",			/* name */
303 	0,				/* snarf */
304 	0,				/* options */
305 	init,				/* init */
306 	load,				/* load */
307 	dump,				/* dump */
308 };
309