xref: /plan9/sys/src/cmd/aux/vga/rgb524mn.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 RGB52x and compatibles.
10  * High Performance Palette DAC.
11  */
12 uchar (*rgb524mnxi)(Vga*, int);
13 void (*rgb524mnxo)(Vga*, int, uchar);
14 
15 enum {						/* index registers */
16 	MiscClock	= 0x02,
17 	SyncControl	= 0x03,
18 	HSyncControl	= 0x04,
19 	PowerMgmnt	= 0x05,
20 	PaletteControl	= 0x07,
21 	SYSCLKControl	= 0x08,
22 	PixelFormat	= 0x0A,
23 	Pixel8Control	= 0x0B,
24 	Pixel16Control	= 0x0C,
25 	Pixel32Control	= 0x0E,
26 	PLLControl1	= 0x10,
27 	PLLControl2	= 0x11,
28 	SYSCLKN		= 0x15,
29 	SYSCLKM		= 0x16,
30 	M0		= 0x20,
31 	N0		= 0x21,
32 	MiscControl1	= 0x70,
33 	MiscControl2	= 0x71,
34 };
35 
36 static void
clock(Vga * vga,Ctlr *,ulong fref,ulong maxpclk)37 clock(Vga* vga, Ctlr*, ulong fref, ulong maxpclk)
38 {
39 	int d, mind;
40 	ulong df, f, m, n, vrf;
41 
42 	mind = vga->f[0]+1;
43 	for(df = 0; df < 4; df++){
44 		for(m = 2; m < 64; m++){
45 			for(n = 2; n < 32; n++){
46 				f = (fref*(m+65))/n;
47 				switch(df){
48 				case 0:
49 					vrf = fref/(n*2);
50 					if(vrf > maxpclk/4 || vrf < 1000000)
51 						continue;
52 					f /= 8;
53 					break;
54 				case 1:
55 					vrf = fref/(n*2);
56 					if(vrf > maxpclk/2 || vrf < 1000000)
57 						continue;
58 					f /= 4;
59 					break;
60 				case 2:
61 					vrf = fref/(n*2);
62 					if(vrf > maxpclk || vrf < 1000000)
63 						continue;
64 					f /= 2;
65 					break;
66 				case 3:
67 					vrf = fref/n;
68 					if(vrf > maxpclk || vrf < 1000000)
69 						continue;
70 					break;
71 				}
72 				if(f > maxpclk)
73 					continue;
74 
75 				d = vga->f[0] - f;
76 				if(d < 0)
77 					d = -d;
78 				if(d <= mind){
79 					vga->m[0] = m;
80 					vga->n[0] = n;
81 					vga->d[0] = df;
82 					mind = d;
83 				}
84 			}
85 		}
86 	}
87 }
88 
89 static void
init(Vga * vga,Ctlr * ctlr)90 init(Vga* vga, Ctlr* ctlr)
91 {
92 	ulong fref, maxpclk;
93 	char *p, *val;
94 
95 	/*
96 	 * Part comes in at least a -170MHz speed-grade.
97 	 */
98 	maxpclk = 170000000;
99 	if(p = strrchr(ctlr->name, '-'))
100 		maxpclk = strtoul(p+1, 0, 0) * 1000000;
101 
102 	/*
103 	 * If we don't already have a desired pclk,
104 	 * take it from the mode.
105 	 * Check it's within range.
106 	 */
107 	if(vga->f[0] == 0)
108 		vga->f[0] = vga->mode->frequency;
109 	if(vga->f[0] > maxpclk)
110 		error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]);
111 	if(val = dbattr(vga->attr, "rgb524mnrefclk"))
112 		fref = strtol(val, 0, 0);
113 	else
114 		fref = RefFreq;
115 
116 	/*
117 	 * Initialise the PLL parameters.
118 	 * Use m/n pair 2.
119 	 */
120 	clock(vga, ctlr, fref, maxpclk);
121 	vga->i[0] = 2;
122 
123 	ctlr->flag |= Finit;
124 }
125 
126 static void
load(Vga * vga,Ctlr * ctlr)127 load(Vga* vga, Ctlr* ctlr)
128 {
129 	char *val;
130 	int hsyncdelay, x;
131 
132 	if(rgb524mnxi == nil && rgb524mnxo == nil)
133 		error("%s->load: no access routines\n", ctlr->name);
134 
135 	/*
136 	 * Set the m/n values for the desired frequency and
137 	 * set pixel control to use compatibility mode with
138 	 * internal frequency select using the specified set
139 	 * of m/n registers.
140 	 */
141 	rgb524mnxo(vga, M0+vga->i[0]*2, vga->d[0]<<6|vga->m[0]);
142 	rgb524mnxo(vga, N0+vga->i[0]*2, vga->n[0]);
143 	rgb524mnxo(vga, PLLControl2, vga->i[0]);
144 	rgb524mnxo(vga, PLLControl1, 0x03);
145 
146 	/*
147 	 * Enable pixel programming in MiscClock;
148 	 * nothing to do in MiscControl1;
149 	 * set internal PLL clock and !vga in MiscControl2;
150 	 */
151 	x = rgb524mnxi(vga, MiscClock) & ~0x01;
152 	x |= 0x01;
153 	rgb524mnxo(vga, MiscClock, x);
154 
155 	x = rgb524mnxi(vga, MiscControl2) & ~0x41;
156 	x |= 0x41;
157 	rgb524mnxo(vga, MiscControl2, x);
158 
159 	/*
160 	 * Syncs.
161 	 */
162 	x = 0;
163 	if(vga->mode->hsync == '+')
164 		x |= 0x10;
165 	if(vga->mode->vsync == '+')
166 		x |= 0x20;
167 	rgb524mnxo(vga, SyncControl, x);
168 	if(val = dbattr(vga->mode->attr, "hsyncdelay"))
169 		hsyncdelay = strtol(val, 0, 0);
170 	else switch(vga->mode->z){
171 	default:
172 	case 8:
173 		hsyncdelay = 1;
174 		break;
175 	case 15:
176 	case 16:
177 		hsyncdelay = 5;
178 		break;
179 	case 32:
180 		hsyncdelay = 7;
181 		break;
182 	}
183 	rgb524mnxo(vga, HSyncControl, hsyncdelay);
184 
185 rgb524mnxo(vga, SYSCLKM, 0x50);
186 rgb524mnxo(vga, SYSCLKN, 0x08);
187 sleep(50);
188 //rgb524mnxo(vga, SYSCLKM, 0x6F);
189 //rgb524mnxo(vga, SYSCLKN, 0x0F);
190 //sleep(500);
191 
192 	/*
193 	 * Set the palette for the desired format.
194 	 * ****NEEDS WORK FOR OTHER THAN 8-BITS****
195 	 */
196 	rgb524mnxo(vga, PaletteControl, 0x00);
197 	switch(vga->mode->z){
198 	case 8:
199 		rgb524mnxo(vga, PixelFormat, 0x03);
200 		rgb524mnxo(vga, Pixel8Control, 0x00);
201 		break;
202 	case 15:
203 		rgb524mnxo(vga, PixelFormat, 0x04);
204 		rgb524mnxo(vga, Pixel16Control, 0xC4);
205 	case 16:
206 		rgb524mnxo(vga, PixelFormat, 0x04);
207 		rgb524mnxo(vga, Pixel16Control, 0xC6);
208 		break;
209 	case 32:
210 		rgb524mnxo(vga, PixelFormat, 0x06);
211 		rgb524mnxo(vga, Pixel32Control, 0x03);
212 		break;
213 	}
214 }
215 
216 static void
dumpclock(Vga *,Ctlr * ctlr,ulong fref,ulong m,ulong n,char * name)217 dumpclock(Vga*, Ctlr* ctlr, ulong fref, ulong m, ulong n, char* name)
218 {
219 	ulong df, f;
220 
221 	df = (m>>6) & 0x03;
222 	m &= 0x3F;
223 	n &= 0x1F;
224 	if(m == 0 || n == 0)
225 		return;
226 	f = (fref*(m+65))/n;
227 	switch(df){
228 	case 0:
229 		f /= 8;
230 		break;
231 	case 1:
232 		f /= 4;
233 		break;
234 	case 2:
235 		f /= 2;
236 		break;
237 	case 3:
238 		break;
239 	}
240 	printitem(ctlr->name, name);
241 	Bprint(&stdout, "%12lud\n", f);
242 }
243 
244 static void
dump(Vga * vga,Ctlr * ctlr)245 dump(Vga* vga, Ctlr* ctlr)
246 {
247 	int i;
248 	char *val;
249 	uchar x[256];
250 	ulong fref, fs;
251 
252 	if(rgb524mnxi == nil && rgb524mnxo == nil)
253 		error("%s->dump: no access routines\n", ctlr->name);
254 
255 	printitem(ctlr->name, "index00");
256 	for(i = 0x00; i < 0x0F; i++){
257 		x[i] = rgb524mnxi(vga, i);
258 		printreg(x[i]);
259 	}
260 	printitem(ctlr->name, "index10");
261 	for(i = 0x10; i < 0x18; i++){
262 		x[i] = rgb524mnxi(vga, i);
263 		printreg(x[i]);
264 	}
265 	printitem(ctlr->name, "index20");
266 	for(i = 0x20; i < 0x30; i++){
267 		x[i] = rgb524mnxi(vga, i);
268 		printreg(x[i]);
269 	}
270 	printitem(ctlr->name, "index30");
271 	for(i = 0x30; i < 0x39; i++){
272 		x[i] = rgb524mnxi(vga, i);
273 		printreg(x[i]);
274 	}
275 	printitem(ctlr->name, "index40");
276 	for(i = 0x40; i < 0x49; i++){
277 		x[i] = rgb524mnxi(vga, i);
278 		printreg(x[i]);
279 	}
280 	printitem(ctlr->name, "index60");
281 	for(i = 0x60; i < 0x63; i++){
282 		x[i] = rgb524mnxi(vga, i);
283 		printreg(x[i]);
284 	}
285 	printitem(ctlr->name, "index70");
286 	for(i = 0x70; i < 0x73; i++){
287 		x[i] = rgb524mnxi(vga, i);
288 		printreg(x[i]);
289 	}
290 	printitem(ctlr->name, "index8E");
291 	for(i = 0x8E; i < 0x92; i++){
292 		x[i] = rgb524mnxi(vga, i);
293 		printreg(x[i]);
294 	}
295 
296 	if(val = dbattr(vga->attr, "rgb524mnrefclk"))
297 		fref = strtol(val, 0, 0);
298 	else
299 		fref = RefFreq;
300 	if(!(x[SYSCLKControl] & 0x04))
301 		dumpclock(vga, ctlr, fref, x[0x16], x[0x15], "sysclk");
302 	fs = x[PLLControl1] & 0x07;
303 	if(fs == 0x01 || fs == 0x03){
304 		if(fs == 0x01)
305 			i = ((vga->misc>>2) & 0x03)*2;
306 		else
307 			i = x[PLLControl2] & 0x07;
308 		dumpclock(vga, ctlr, fref, x[M0+i*2], x[N0+i*2], "pllclk");
309 	}
310 }
311 
312 Ctlr rgb524mn = {
313 	"rgb524mn",			/* name */
314 	0,				/* snarf */
315 	0,				/* options */
316 	init,				/* init */
317 	load,				/* load */
318 	dump,				/* dump */
319 };
320