xref: /plan9/sys/src/cmd/aux/vga/ct65540.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 enum
9 {
10 	X=	0x3D6,	/* index reg */
11 	D=	0x3D7,	/* data reg */
12 };
13 
14 static int misc[] = {	0x0,  0x1,  0x2,  0x3,  0x4,  0x5,  0x6,  0xE, 0x28, 0x29,
15 			0x70, 0x72, 0x73, 0x7D, 0x7F, -1};
16 static int map[] = {	0x7,  0x8,  0xB,  0xC,  0x10, 0x11, -1};
17 static int flags[] = {	0xF,  0x2B, 0x44, 0x45, -1};
18 static int compat[] = {	0x14, 0x15, 0x1F, 0x7E, -1};
19 static int clock[] = {	0x30, 0x31, 0x32, 0x33, -1};
20 static int mm[] = {	0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, -1};
21 static int alt[] = {	0x0D, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E,
22 			0x24, 0x25, 0x26, 0x64, 0x65, 0x66, 0x67, -1};
23 static int flat[] = {	0x2C, 0x2D, 0x2E, 0x2F, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54,
24 			0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E,
25 			0x5F, 0x60, 0x61, 0x62, 0x63, 0x68, 0x6C, 0x6E, 0x6F, -1};
26 
27 typedef struct Group Group;
28 struct Group {
29 	char *name;
30 	int *x;
31 };
32 static Group group[] =
33 {
34 	{ "misc", misc, },
35 	{ "map", map, },
36 	{ "compatability", compat, },
37 	{ "clock", clock, },
38 	{ "multimedia", mm, },
39 	{ "alternate", alt, },
40 	{ "flat-panel", flat, },
41 	{ 0 },
42 };
43 
44 static uchar greg[256];
45 
46 static uchar
ctxi(uchar index)47 ctxi(uchar index)
48 {
49 	outportb(X, index);
50 	return inportb(D);
51 }
52 
53 static void
ctxo(uchar index,uchar data)54 ctxo(uchar index, uchar data)
55 {
56 	outportb(X, index);
57 	outportb(D, data);
58 }
59 
60 /*
61  * ct65540.
62  */
63 static void
snarf(Vga *,Ctlr * ctlr)64 snarf(Vga*, Ctlr* ctlr)
65 {
66 	Group *g;
67 	int *xp;
68 
69 	ctlr->flag |= Fsnarf;
70 
71 	for(g = group; g->name; g++)
72 		for(xp = g->x; *xp >= 0; xp++)
73 			greg[*xp] = ctxi(*xp);
74 }
75 
76 static void
options(Vga *,Ctlr * ctlr)77 options(Vga*, Ctlr* ctlr)
78 {
79 	ctlr->flag |= Hlinear|Foptions;
80 }
81 
82 /*
83  *  brute force and ignorance
84  */
85 static int
setclock(Vga * vga)86 setclock(Vga* vga)
87 {
88 	ulong fvco, t;
89 	ulong m, n;
90 	ulong bestm, bestn, diff, bestdiff, lastdiff;
91 	ulong p;
92 
93 	if(vga->mode->frequency > 220000000)
94 		return -1;
95 
96 	vga->misc &= ~(3<<2);
97 	vga->feature &= ~3;
98 	greg[0x33] &= ~0x20;		/* set VCLK not MCLK */
99 	greg[0x33] &= ~0x80;		/* clk0 & clk1 are 25.175 & 28.322 MHz */
100 
101 	vga->misc |= (2<<2);
102 	vga->feature |= 2;
103 
104 	fvco = vga->mode->frequency;
105 	if(fvco == 0)
106 		return -1;
107 	p = 0;
108 	while(fvco < 100000000){
109 		fvco *= 2;
110 		p++;
111 	}
112 
113 	m = (1<<31)/(4*RefFreq);
114 	if(m > 127)
115 		m = 127;
116 	bestdiff = 1<<31;
117 	bestm = 3;
118 	bestn = 3;
119 	for(; m > 2; m--){
120 		lastdiff = 1<<31;
121 		for(n = 3; n < 128; n++){
122 			t = (RefFreq*4*m)/n;
123 			diff = abs(fvco-t);
124 			if(diff < bestdiff){
125 				bestdiff = diff;
126 				bestm = m;
127 				bestn = n;
128 			} else {
129 				if(diff > lastdiff)
130 					break;
131 			}
132 			lastdiff = diff;
133 		}
134 	}
135 
136 	greg[0x31] = bestm - 2;
137 	greg[0x32] = bestn - 2;
138 	greg[0x30] = (p<<1) | 1;
139 	return 0;
140 }
141 
142 static void
init(Vga * vga,Ctlr * ctlr)143 init(Vga* vga, Ctlr* ctlr)
144 {
145 	int x;
146 
147 	greg[0x15] = 0;			/* allow writes to all registers */
148 
149 	if(vga->mode->z > 8)
150 		error("depth %d not supported\n", vga->mode->z);
151 
152 	if(vga->mode->z == 8){
153 		if(vga->linear && (ctlr->flag & Hlinear))
154 			ctlr->flag |= Ulinear;
155 		vga->vmz = 1024*1024;
156 		vga->vmb = 1024*1024;
157 
158 		/* linear mapping - extension regs*/
159 		greg[0x04] = (1<<2);	/* enable CRTC bits 16 & 17, 32 bit mode */
160 		greg[0x0b] = 0x15;	/* linear addressing, > 256k, sequential addr */
161 		greg[0x28] = 0x90;	/* non-interlaced, 256 colors */
162 
163 		/* normal regs */
164 		vga->sequencer[0x04] = 0x0A;	/* sequential memory access */
165 		vga->graphics[0x05] = 0x00;	/* sequential access, shift out 8 bits at */
166 						/* a time */
167 		vga->attribute[0x10] &= ~(1<<6); /* 1 dot clock per pixel */
168 		vga->crt[0x14] = 0x00;
169 		vga->crt[0x17] = 0xe3;		/* always byte mode */
170 	} else {
171 		/* mapped to 0xa0000 - extension regs*/
172 		greg[0x04] = (1<<2);	/* enable CRTC bits 16 & 17, 32 bit mode */
173 		greg[0x0b] = 0x01;	/* 0xA0000 - 0xAFFFF, planar addressing */
174 		greg[0x28] = 0x80;	/* non-interlaced, 16 colors */
175 	}
176 
177 	/* the extension registers have even more overflow bits */
178 	x = 0;
179 	if(vga->mode->vt & (1<<10))
180 		x |= (1<<0);
181 	if(vga->mode->vrs & (1<<10))
182 		x |= (1<<2);
183 	greg[0x16] = x;
184 	x = 0;
185 	if(vga->mode->ht & (1<<(8+3)))
186 		x |= (1<<0);
187 	if(vga->mode->shb & (1<<(8+3)))
188 		x |= (1<<4);
189 	if(vga->mode->ehb & (1<<(6+3)))
190 		x |= (1<<5);
191 	greg[0x17] = x;
192 
193 	if(vga->mode->y > 480)
194 		vga->misc &= 0x3F;
195 
196 	setclock(vga);
197 
198 	ctlr->flag |= Finit;
199 }
200 
201 static void
load(Vga * vga,Ctlr * ctlr)202 load(Vga* vga, Ctlr* ctlr)
203 {
204 	Group *g;
205 	int *xp;
206 
207 	/* must be first */
208 	ctxo(0x15, greg[0x15]);	/* write protect */
209 	ctxo(0x33, greg[0x33]);	/* select clock */
210 
211 	if(ctlr->flag & Ulinear){
212 		greg[0x8] = vga->vmb>>20;
213 		ctxo(0x08, greg[0x08]);
214 	}
215 
216 	/* only write what changed */
217 	for(g = group; g->name; g++)
218 		for(xp = g->x; *xp >= 0; xp++)
219 			ctxo(*xp, greg[*xp]);
220 
221 	ctlr->flag |= Fload;
222 }
223 
224 static void
dump(Vga *,Ctlr * ctlr)225 dump(Vga*, Ctlr* ctlr)
226 {
227 	Group *g;
228 	int *xp;
229 	char *name;
230 	int lastx;
231 	char item[32];
232 
233 	name = ctlr->name;
234 
235 	for(g = group; g->name; g++){
236 		lastx = -2;
237 		for(xp = g->x; *xp >= 0; xp++){
238 			if(*xp != lastx+1){
239 				sprint(item, "%s %2.2ux:", g->name, *xp);
240 				printitem(name, item);
241 			}
242 			lastx = *xp;
243 			printreg(greg[*xp]);
244 		}
245 	}
246 }
247 
248 Ctlr ct65540 = {
249 	"ct65540",			/* name */
250 	snarf,				/* snarf */
251 	options,			/* options */
252 	init,				/* init */
253 	load,				/* load */
254 	dump,				/* dump */
255 };
256 
257 Ctlr ct65545 = {
258 	"ct65545",			/* name */
259 	snarf,				/* snarf */
260 	options,			/* options */
261 	init,				/* init */
262 	load,				/* load */
263 	dump,				/* dump */
264 };
265 
266 Ctlr ct65545hwgc = {
267 	"ct65545hwgc",			/* name */
268 	0,				/* snarf */
269 	0,				/* options */
270 	0,				/* init */
271 	0,				/* load */
272 	0,				/* dump */
273 };
274