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