xref: /plan9/sys/src/cmd/aux/vga/i81x.c (revision 14cc0f535177405a84c5b73603a98e5db6674719)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 
5 #include "pci.h"
6 #include "vga.h"
7 
8 /*
9  * Intel 81x chipset family.
10  *   mem[0]: AGP aperture memory, 64MB for 810-DC100, from 0xF4000000
11  *   mem[1]: GC Register mmio space, 512KB for 810-DC100, from 0xFF000000
12  *   For the memory of David Hogan, died April 9, 2003,  who wrote this driver
13  *   first for LCD.
14  *                   August 28, 2003 Kenji Okamoto
15  */
16 
17 typedef struct {
18 	Pcidev*	pci;
19 	uchar*	mmio;
20 	ulong	clk[6];
21 	ulong	lcd[9];
22 	ulong	pixconf;
23 } I81x;
24 
25 static void
snarf(Vga * vga,Ctlr * ctlr)26 snarf(Vga* vga, Ctlr* ctlr)
27 {
28 	int f, i;
29 	uchar *mmio;
30 	ulong *rp;
31 	Pcidev *p;
32 	I81x *i81x;
33 
34 	if(vga->private == nil){
35 		vga->private = alloc(sizeof(I81x));
36 		p = nil;
37 		while((p = pcimatch(p, 0x8086, 0)) != nil) {
38 			switch(p->did) {
39 			default:
40 				continue;
41 			case 0x7121:	/* Vanilla 82810 */
42 			case 0x7123:	/* 810-DC100, DELL OptiPlex GX100 */
43 			case 0x7125:	/* 82810E */
44 			case 0x1102:	/* 82815 FSB limited to 100MHz */
45 			case 0x1112:	/* 82815 no AGP */
46 			case 0x1132:	/* 82815 fully featured Solano */
47 			case 0x3577:	/* IBM R31 uses intel 830M chipset */
48 				vga->f[1] = 230000000;		/* MAX speed of internal DAC (Hz)*/
49 				break;
50 			}
51 			break;
52 		}
53 		if(p == nil)
54 			error("%s: Intel 81x graphics function not found\n", ctlr->name);
55 
56 		if((f = open("#v/vgactl", OWRITE)) < 0)
57 			error("%s: can't open vgactl\n", ctlr->name);
58 		if(write(f, "type i81x", 9) != 9)
59 			error("%s: can't set type\n", ctlr->name);
60 		close(f);
61 
62 		mmio = segattach(0, "i81xmmio", 0, p->mem[1].size);
63 		if(mmio == (void*)-1)
64 			error("%s: can't attach mmio segment\n", ctlr->name);
65 
66 		i81x = vga->private;
67 		i81x->pci = p;
68 		i81x->mmio = mmio;
69 	}
70 	i81x = vga->private;
71 
72 	/* must give aperture memory size for frame buffer memory
73 		such as 64*1024*1024 */
74 	vga->vma = vga->vmz = i81x->pci->mem[0].size;
75 //	vga->vmz = 8*1024*1024;
76 	vga->apz = i81x->pci->mem[0].size;
77 	ctlr->flag |= Hlinear;
78 
79 	vga->graphics[0x10] = vgaxi(Grx, 0x10);
80 	vga->attribute[0x11] = vgaxi(Attrx, 0x11);	/* overscan color */
81 	for(i=0; i < 0x19; i++)
82 		vga->crt[i] = vgaxi(Crtx, i);
83 	for(i=0x30; i <= 0x82; i++)		/* set CRT Controller Register (CR) */
84 		vga->crt[i] = vgaxi(Crtx, i);
85 	/* 0x06000: Clock Control Register base address (3 VCO frequency control) */
86 	rp = (ulong*)(i81x->mmio+0x06000);
87 	for(i = 0; i < nelem(i81x->clk); i++)
88 		i81x->clk[i] = *rp++;
89 
90 	/* i830 CRTC registers (A) */
91 	rp = (ulong*)(i81x->mmio+0x60000);
92 	for(i = 0; i < nelem(i81x->lcd); i++)
93 		i81x->lcd[i] = *rp++;
94 	rp = (ulong*)(i81x->mmio+0x70008);	/* Pixel Pipeline Control register A */
95 	i81x->pixconf = *rp;
96 
97 	ctlr->flag |= Fsnarf;
98 }
99 
100 static void
options(Vga *,Ctlr * ctlr)101 options(Vga*, Ctlr* ctlr)
102 {
103 	ctlr->flag |= Hlinear|Foptions;
104 }
105 
106 static void
i81xdclk(I81x * i81x,Vga * vga)107 i81xdclk(I81x *i81x, Vga *vga)		/* freq = MHz */
108 {
109 	int m, n, post, mtp, ntp;
110 	double md, freq, error;
111 
112 	freq = vga->mode->deffrequency/1000000.0;
113 	if (freq == 0)
114 		sysfatal("i81xdclk: deffrequency %d becomes freq 0.0",
115 			vga->mode->deffrequency);
116 	post = log(600.0/freq)/log(2.0);
117 
118 	for(ntp=3;;ntp++) {
119 		md = freq*(1<<post)/(24.0/(double)ntp)/4.0;
120 		mtp = (int)(md+0.5);
121 		if(mtp<3) mtp=3;
122 		error = 1.0-freq/(md/(ntp*(1<<post))*4*24.0);
123 		if((fabs(error) < 0.001) || ((ntp > 30) && (fabs(error) < 0.005)))
124 			break;
125 	}
126 	m = vga->m[1] = mtp-2;
127 	n = vga->n[1] = ntp-2;
128 	vga->r[1] = post;
129 	i81x->clk[2] = ((n & 0x3FF)<<16) | (m & 0x3FF);
130 	i81x->clk[4] = (i81x->clk[4] & ~0x700000) | ((post & 0x07)<<20);
131 	vga->mode->frequency = (m+2)/((n+2)*(1<<post))*4*24*1000000;
132 }
133 
134 static void
init(Vga * vga,Ctlr * ctlr)135 init(Vga* vga, Ctlr* ctlr)
136 {
137 	I81x *i81x;
138 	int vt, vde, vrs, vre;
139 	ulong *rp;
140 
141 	i81x = vga->private;
142 
143 	/* <<TODO>>
144 	    i81x->clk[3]: LCD_CLKD: 0x0600c~0x0600f, default=00030013h
145 			(VCO N-divisor=03h, M-divisor=13h)
146 	    i81x->clk[4]: DCLK_0DS: 0x06010~0x06013, Post value, default=40404040h means
147 		Post Divisor=16, VCO Loop divisor = 4xM for all clocks.
148 	    Display&LCD Clock Devisor Select Reg = 0x40404040 ==> (LCD)(Clock2)(Clock1)(Clock0)
149 	*/
150 	i81x->clk[0] = 0x00030013;
151 	i81x->clk[1] = 0x00100053;
152 	rp = (ulong*)i81x->mmio+0x6010;
153 	i81x->clk[4] = *rp;
154 	i81x->clk[4] |= 0x4040;
155 	vga->misc = vgai(MiscR);
156 	switch(vga->virtx) {
157 	case 640:	/* 640x480 DCLK_0D 25.175MHz dot clock */
158 		vga->misc &=  ~0x0A;
159 		break;
160 	case 720:	/* 720x480 DCLK_1D 28.322MHz dot clock */
161 		vga->misc = (vga->misc & ~0x08) | (1<<2);
162 		break;
163 	case 800:
164 	case 1024:
165 	case 1152:
166 	case 1280:
167 	case 1376:
168 		vga->misc = vga->misc | (2<<2) & ~0x02;		/* prohibit to access frame buffer */
169 		i81xdclk(i81x, vga);
170 		break;
171 	default:	/* for other higher resolution DCLK_2D */
172 		error("%s: Only 800, 1024, 1152, 1280, 1376 resolutions are supported\n", ctlr->name);
173 	}
174 
175 	/*	<<TODO>>
176 		i830 LCD Controller, at i81x->mmio+0x60000
177 		i81x->lcd[0]: Horizontal Total Reg.		0x60000
178 		i81x->lcd[1]: Horizontal Blanking Reg.	0x60004
179 		i81x->lcd[2]: Horizontal Sync Reg. 		0x60008
180 		i81x->lcd[3]: Vertical Total Reg.		0x6000c
181 		i81x->lcd[4]: Vertical Blanking Reg.		0x60010
182 		i81x->lcd[5]: Vertical Sync Reg. 		0x60014
183 		i81x->lcd[6]: Pixel Pipeline A Sequencer Register Control(SRC,0~7)	0x6001c
184 		i81x->lcd[7]: BCLRPAT_A	0x60020
185 	         i81x->lcd[8]: 0
186 	*/
187 	/*
188 	 * Pixel pipeline control register 0x70008:
189 	 *    16/24bp bypasses palette,
190 	 *    hw cursor enabled(1<<12), hi-res mode(1<<0), depth(16-19 bit)
191 	 *    8bit DAC enable (1<<15), don't wrap to 256kM memory of VGA(1<<1).
192 	 *    enable extended palette addressing (1<<8)
193 	*/
194 	i81x->pixconf = (1<<12)|(1<<0);
195 	i81x->pixconf &= 0xFFFFFBFF;	/* disable overscan color */
196 	switch(vga->mode->z) {		/* vga->mode->z: color depth */
197 	case 8:
198 		i81x->pixconf |= (2<<16);
199 		break;
200 	case 16:	/* (5:6:5 bit) */
201 		i81x->pixconf |= (5<<16);
202 		break;
203 	case 24:
204 		i81x->pixconf |= (6<<16);
205 		break;
206 	case 32:		/* not supported */
207 		i81x->pixconf |= (7<<16);
208 		break;
209 	default:
210 		error("%s: depth %d not supported\n", ctlr->name, vga->mode->z);
211 	}
212 
213 	/* DON'T CARE of Sequencer Reg. */
214 	/* DON'T CARE of Attribute registers other than this */
215 	vga->attribute[0x11] = 0;		/* over scancolor = black */
216 	/* DON't CARE of graphics[1], [2], [3], [4], [5], [6], [7] and [8] value */
217 	if(vga->linear && (ctlr->flag & Hlinear)) {
218 	/* enable linear mapping, no VGA memory and no page mapping */
219 		vga->graphics[0x10] = 0x0A;
220 		ctlr->flag |= Ulinear;
221 	}
222 
223 	vt = vga->mode->vt;
224 	vde = vga->virty;
225 	vrs = vga->mode->vrs;
226 	vre = vga->mode->vre+6;		/* shift 7 pixel up */
227 
228 	if(vga->mode->interlace == 'v') {
229 		vt /= 2;
230 		vde /= 2;
231 		vrs /= 2;
232 		vre /= 2;
233 	}
234 		/* Reset Row scan */
235 	vga->crt[8] = 0;
236 /* Line Compare, bit 6 of crt[9], bit 4 of crt[7] and crt[0x18], should be
237  *	vga->crt[9] = vgaxi(Crtx, 9) | ((vde>>9 & 1)<<6) & 0x7F;
238  *	vga->crt[7] = vgaxi(Crtx, 7) | ((vde>>8 & 1)<<4);
239  *	vga->crt[0x18] = vde & 0xFF;
240  *      However, above values don't work!!  I don't know why.   K.Okamoto
241  */
242 	vga->crt[9] = 0;		/* I don't know why ? */
243 	vga->crt[7] = 0;		/* I don't know why ? */
244 	vga->crt[0x18] = 0;		/* I don't know why ? */
245 /*	32 bits Start Address of frame buffer (AGP aperture memory)
246 	vga->crt[0x42] = MSB 8 bits of Start Address Register, extended high start address Reg.
247 	vga->crt[0x40] = higer 6 bits in 0~5 bits, and the MSB = 1, extebded start address Reg.
248 	vga->crt[0x0C] = Start Address High Register
249 	vga->crt[0x0D] = Start Address Low Register
250 	LSB 2 bits of Start Address are always 0
251  */
252 	vga->crt[0x42] = vga->pci->mem[0].bar>>24 & 0xFF;
253 	vga->crt[0x40] = vga->pci->mem[0].bar>>18 & 0x3F | 0x80;
254 		/* Start Address High */
255 	vga->crt[0x0C] = vga->pci->mem[0].bar>>10 & 0xFF;
256 		/* Start Address Low */
257 	vga->crt[0x0D] = (vga->pci->mem[0].bar >>2 + 1)& 0xFF;
258 		/* Underline Location, Memory Mode, DON'T CARE THIS VALUE */
259 	vga->crt[0x14] = 0x0;
260 		/* CRT Mode Control */
261 	vga->crt[0x17] = 0x80;		/* CRT normal mode */
262 		/* Frame buffer memory offset  (memory amount for a line) */
263 		/* vga->crt[0x13] = lower 8 bits of Offset Register
264 			vga->crt[0x41] = MSB 4 bits, those value should be
265 			vga->crt[0x13] = (vga->virtx*(vga->mode->z>>3)/4) & 0xFF;
266 			vga->crt[0x41] = (vga->virtx*(vga->mode->z>>3)/4)>>8 & 0x0F;
267 		  However, those doesn't work properly  K.Okamoto
268 		*/
269 	vga->crt[0x41] = (vga->crt[0x13]>>8) & 0x0F;		//dhog
270 
271 		/* Horizontal Total */
272 	vga->crt[0] = ((vga->mode->ht>>3)-6) & 0xFF;
273 		/* Extended Horizontal Total Time Reg (ht)  */
274 	vga->crt[0x35] = vga->mode->ht>>12 & 0x01;
275 //	vga->crt[0x35] = (((vga->mode->ht>>1)-5)>>8) & 0x01;	//dhog
276 		/* Horizontal Display Enable End == horizontal width */
277 	vga->crt[1] = (vga->virtx-1)>>3 & 0xFF;
278 		/* Horizontal Blanking Start */
279 	vga->crt[2] = ((vga->mode->shb>>3)-1) & 0xFF;
280 		/* Horizontal blanking End crt[39](0),crt[5](7),crt[3](4:0) */
281 	vga->crt[3] = (vga->mode->shb - vga->virtx)>>3 & 0x1F;
282 	vga->crt[5] = ((vga->mode->shb - vga->virtx)>>3 & 0x20) <<2;
283 	vga->crt[0x39] = ((vga->mode->shb - vga->virtx)>>3 & 0x40) >>6;
284 //	vga->crt[0x39] = (vga->mode->ehb>>9) & 0x01;		//dhog
285 		/* Horizontal Sync Start */
286 	vga->crt[4] = vga->mode->shb>>3 & 0xFF;
287 		/* Horizontal Sync End */
288 	vga->crt[5] |= vga->mode->ehb>>3 & 0x1F;
289 		/* Extended Vertical Total (vt) */
290 	vga->crt[6] = (vt - 2) & 0xFF;
291 	vga->crt[0x30] = (vt - 2)>>8 & 0x0F;
292 		/* Vertical Sync Period */
293 	vga->crt[0x11] = (vre - vrs - 2) & 0x0F;
294 		/* Vertical Blanking End  */
295 	vga->crt[0x16] = (vre - vrs) & 0xFF;
296 		/* Extended Vertical Display End (y) */
297 	vga->crt[0x12] = (vde-1) & 0xFF;
298 	vga->crt[0x31] = (vde-1)>>8 & 0x0f;
299 		/* Extended Vertical Sync Start (vrs)  */
300 	vga->crt[0x10] = (vrs-1) & 0xFF;
301 	vga->crt[0x32] = (vrs-1)>>8 & 0x0F;
302 		/* Extended Vertical Blanking Start (vrs) */
303 	vga->crt[0x15] = vrs & 0xFF;
304 	vga->crt[0x33] = vrs>>8 & 0x0F;
305 
306 	if(vga->mode->interlace == 'v')
307 		vga->crt[0x70] = vrs | 0x80;
308 	else
309 		vga->crt[0x70] = 0;
310 	vga->crt[0x80] = 1;
311 
312 	ctlr->flag |= Finit;
313 }
314 
315 static void
load(Vga * vga,Ctlr * ctlr)316 load(Vga* vga, Ctlr* ctlr)
317 {
318 	int i;
319 	ulong *rp;
320 	I81x *i81x;
321 	char *p;
322 
323 	i81x = vga->private;
324 
325 	vgaxo(Attrx, 0x11, vga->attribute[0x11]);
326 	/* set the screen graphic mode */
327 	vgaxo(Crtx, 0x80, vga->crt[0x80]);
328 	vgaxo(Grx, 0x10, vga->graphics[0x10]);
329 	vgao(MiscW, vga->misc);
330 	for(i=0; i <= 0x18; i++)
331 		vgaxo(Crtx, i, vga->crt[i]);
332 	for(i=0x30; i <= 0x82; i++)
333 		vgaxo(Crtx, i, vga->crt[i]);
334 	vga->crt[0x40] |= 0x80;			/* set CR40, then set the MSB bit of it */
335 	vgaxo(Crtx, 0x40, vga->crt[0x40]);
336 	/* 0x06000 = offset of Vertical Clock Devisor VGA0 */
337 	rp = (ulong*)(i81x->mmio+0x06000);
338 	for(i=0; i < nelem(i81x->clk); i++)
339 		*rp++ = i81x->clk[i];
340 	rp = (ulong*)(i81x->mmio+0x60000);
341 	for(i = 0; i < nelem(i81x->lcd); i++)
342 		*rp++ = i81x->lcd[i];
343 	/* set cursor, graphic mode */
344 	rp = (ulong*)(i81x->mmio+0x70008);
345 	*rp = i81x->pixconf | (1<<8);
346 
347 	p = (char*)(i81x->mmio+Pixmask);	/* DACMASK */
348 	*p = 0xff;
349 	p = (char*)(i81x->mmio+PaddrW);		/* DACWX */
350 	*p = 0x04;
351 	p = (char*)(i81x->mmio+Pdata);		/* DACDATA */
352 	*p = 0xff;
353 	*p = 0xff;
354 	*p = 0xff;
355 	*p = 0x00;
356 	*p = 0x00;
357 	*p = 0x00;
358 	*rp = i81x->pixconf;
359 
360 	ctlr->flag |= Fload;
361 }
362 
363 static void
dump(Vga * vga,Ctlr * ctlr)364 dump(Vga* vga, Ctlr* ctlr)
365 {
366 	int i;
367 	Pcidev *p;
368 	I81x *i81x;
369 	char *name;
370 
371 	name = ctlr->name;
372 	i81x = vga->private;
373 
374 	printitem(name, "Crt30");
375 	for(i = 0x30; i <= 0x39; i++)
376 		printreg(vga->crt[i]);
377 
378 	printitem(name, "Crt40");
379 	for(i = 0x40; i <= 0x42; i++)
380 		printreg(vga->crt[i]);
381 
382 	printitem(name, "Crt70");
383 	for(i = 0x70; i <= 0x79; i++)
384 		printreg(vga->crt[i]);
385 
386 	printitem(name, "Crt80");
387 	for(i = 0x80; i <= 0x82; i++)
388 		printreg(vga->crt[i]);
389 
390 	printitem(name, "Graphics10");
391 	for(i = 0x10; i <= 0x1f; i++)
392 		printreg(vga->graphics[i]);
393 
394 	printitem(name, "clk");
395 	for(i = 0; i < nelem(i81x->clk); i++)
396 		printreg(i81x->clk[i]);
397 
398 	printitem(name, "lcd");
399 	for(i = 0; i < nelem(i81x->lcd); i++)
400 		printreg(i81x->lcd[i]);
401 
402 	printitem(name, "pixconf");
403 	printreg(i81x->pixconf);
404 
405 	p = i81x->pci;
406 	printitem(name, "mem[0]");
407 	Bprint(&stdout, "base %lux size %d\n", p->mem[0].bar & ~0x0F, p->mem[0].size);
408 
409 	printitem(name, "mem[1]");
410 	Bprint(&stdout, "base %lux size %d\n", p->mem[1].bar & ~0x0F, p->mem[1].size);
411 
412 }
413 
414 Ctlr i81x = {
415 	"i81x",			/* name */
416 	snarf,				/* snarf */
417 	options,			/* options */
418 	init,				/* init */
419 	load,				/* load */
420 	dump,				/* dump */
421 };
422 
423 Ctlr i81xhwgc = {
424 	"i81xhwgc",			/* name */
425 	0,				/* snarf */
426 	0,				/* options */
427 	0,				/* init */
428 	0,				/* load */
429 	0,				/* dump */
430 };
431