diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/aux/vga/i81x.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/aux/vga/i81x.c')
-rwxr-xr-x | sys/src/cmd/aux/vga/i81x.c | 430 |
1 files changed, 430 insertions, 0 deletions
diff --git a/sys/src/cmd/aux/vga/i81x.c b/sys/src/cmd/aux/vga/i81x.c new file mode 100755 index 000000000..b1fdf74be --- /dev/null +++ b/sys/src/cmd/aux/vga/i81x.c @@ -0,0 +1,430 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> + +#include "pci.h" +#include "vga.h" + +/* + * Intel 81x chipset family. + * mem[0]: AGP aperture memory, 64MB for 810-DC100, from 0xF4000000 + * mem[1]: GC Register mmio space, 512KB for 810-DC100, from 0xFF000000 + * For the memory of David Hogan, died April 9, 2003, who wrote this driver + * first for LCD. + * August 28, 2003 Kenji Okamoto + */ + +typedef struct { + Pcidev* pci; + uchar* mmio; + ulong clk[6]; + ulong lcd[9]; + ulong pixconf; +} I81x; + +static void +snarf(Vga* vga, Ctlr* ctlr) +{ + int f, i; + uchar *mmio; + ulong *rp; + Pcidev *p; + I81x *i81x; + + if(vga->private == nil){ + vga->private = alloc(sizeof(I81x)); + p = nil; + while((p = pcimatch(p, 0x8086, 0)) != nil) { + switch(p->did) { + default: + continue; + case 0x7121: /* Vanilla 82810 */ + case 0x7123: /* 810-DC100, DELL OptiPlex GX100 */ + case 0x7125: /* 82810E */ + case 0x1102: /* 82815 FSB limited to 100MHz */ + case 0x1112: /* 82815 no AGP */ + case 0x1132: /* 82815 fully featured Solano */ + case 0x3577: /* IBM R31 uses intel 830M chipset */ + vga->f[1] = 230000000; /* MAX speed of internal DAC (Hz)*/ + break; + } + break; + } + if(p == nil) + error("%s: Intel 81x graphics function not found\n", ctlr->name); + + if((f = open("#v/vgactl", OWRITE)) < 0) + error("%s: can't open vgactl\n", ctlr->name); + if(write(f, "type i81x", 9) != 9) + error("%s: can't set type\n", ctlr->name); + close(f); + + mmio = segattach(0, "i81xmmio", 0, p->mem[1].size); + if(mmio == (void*)-1) + error("%s: can't attach mmio segment\n", ctlr->name); + + i81x = vga->private; + i81x->pci = p; + i81x->mmio = mmio; + } + i81x = vga->private; + + /* must give aperture memory size for frame buffer memory + such as 64*1024*1024 */ + vga->vma = vga->vmz = i81x->pci->mem[0].size; +// vga->vmz = 8*1024*1024; + vga->apz = i81x->pci->mem[0].size; + ctlr->flag |= Hlinear; + + vga->graphics[0x10] = vgaxi(Grx, 0x10); + vga->attribute[0x11] = vgaxi(Attrx, 0x11); /* overscan color */ + for(i=0; i < 0x19; i++) + vga->crt[i] = vgaxi(Crtx, i); + for(i=0x30; i <= 0x82; i++) /* set CRT Controller Register (CR) */ + vga->crt[i] = vgaxi(Crtx, i); + /* 0x06000: Clock Control Register base address (3 VCO frequency control) */ + rp = (ulong*)(i81x->mmio+0x06000); + for(i = 0; i < nelem(i81x->clk); i++) + i81x->clk[i] = *rp++; + + /* i830 CRTC registers (A) */ + rp = (ulong*)(i81x->mmio+0x60000); + for(i = 0; i < nelem(i81x->lcd); i++) + i81x->lcd[i] = *rp++; + rp = (ulong*)(i81x->mmio+0x70008); /* Pixel Pipeline Control register A */ + i81x->pixconf = *rp; + + ctlr->flag |= Fsnarf; +} + +static void +options(Vga*, Ctlr* ctlr) +{ + ctlr->flag |= Hlinear|Foptions; +} + +static void +i81xdclk(I81x *i81x, Vga *vga) /* freq = MHz */ +{ + int m, n, post, mtp, ntp; + double md, freq, error; + + freq = vga->mode->deffrequency/1000000.0; + if (freq == 0) + sysfatal("i81xdclk: deffrequency %d becomes freq 0.0", + vga->mode->deffrequency); + post = log(600.0/freq)/log(2.0); + + for(ntp=3;;ntp++) { + md = freq*(1<<post)/(24.0/(double)ntp)/4.0; + mtp = (int)(md+0.5); + if(mtp<3) mtp=3; + error = 1.0-freq/(md/(ntp*(1<<post))*4*24.0); + if((fabs(error) < 0.001) || ((ntp > 30) && (fabs(error) < 0.005))) + break; + } + m = vga->m[1] = mtp-2; + n = vga->n[1] = ntp-2; + vga->r[1] = post; + i81x->clk[2] = ((n & 0x3FF)<<16) | (m & 0x3FF); + i81x->clk[4] = (i81x->clk[4] & ~0x700000) | ((post & 0x07)<<20); + vga->mode->frequency = (m+2)/((n+2)*(1<<post))*4*24*1000000; +} + +static void +init(Vga* vga, Ctlr* ctlr) +{ + I81x *i81x; + int vt, vde, vrs, vre; + ulong *rp; + + i81x = vga->private; + + /* <<TODO>> + i81x->clk[3]: LCD_CLKD: 0x0600c~0x0600f, default=00030013h + (VCO N-divisor=03h, M-divisor=13h) + i81x->clk[4]: DCLK_0DS: 0x06010~0x06013, Post value, default=40404040h means + Post Divisor=16, VCO Loop divisor = 4xM for all clocks. + Display&LCD Clock Devisor Select Reg = 0x40404040 ==> (LCD)(Clock2)(Clock1)(Clock0) + */ + i81x->clk[0] = 0x00030013; + i81x->clk[1] = 0x00100053; + rp = (ulong*)i81x->mmio+0x6010; + i81x->clk[4] = *rp; + i81x->clk[4] |= 0x4040; + vga->misc = vgai(MiscR); + switch(vga->virtx) { + case 640: /* 640x480 DCLK_0D 25.175MHz dot clock */ + vga->misc &= ~0x0A; + break; + case 720: /* 720x480 DCLK_1D 28.322MHz dot clock */ + vga->misc = (vga->misc & ~0x08) | (1<<2); + break; + case 800: + case 1024: + case 1152: + case 1280: + case 1376: + vga->misc = vga->misc | (2<<2) & ~0x02; /* prohibit to access frame buffer */ + i81xdclk(i81x, vga); + break; + default: /* for other higher resolution DCLK_2D */ + error("%s: Only 800, 1024, 1152, 1280, 1376 resolutions are supported\n", ctlr->name); + } + + /* <<TODO>> + i830 LCD Controller, at i81x->mmio+0x60000 + i81x->lcd[0]: Horizontal Total Reg. 0x60000 + i81x->lcd[1]: Horizontal Blanking Reg. 0x60004 + i81x->lcd[2]: Horizontal Sync Reg. 0x60008 + i81x->lcd[3]: Vertical Total Reg. 0x6000c + i81x->lcd[4]: Vertical Blanking Reg. 0x60010 + i81x->lcd[5]: Vertical Sync Reg. 0x60014 + i81x->lcd[6]: Pixel Pipeline A Sequencer Register Control(SRC,0~7) 0x6001c + i81x->lcd[7]: BCLRPAT_A 0x60020 + i81x->lcd[8]: 0 + */ + /* + * Pixel pipeline control register 0x70008: + * 16/24bp bypasses palette, + * hw cursor enabled(1<<12), hi-res mode(1<<0), depth(16-19 bit) + * 8bit DAC enable (1<<15), don't wrap to 256kM memory of VGA(1<<1). + * enable extended palette addressing (1<<8) + */ + i81x->pixconf = (1<<12)|(1<<0); + i81x->pixconf &= 0xFFFFFBFF; /* disable overscan color */ + switch(vga->mode->z) { /* vga->mode->z: color depth */ + case 8: + i81x->pixconf |= (2<<16); + break; + case 16: /* (5:6:5 bit) */ + i81x->pixconf |= (5<<16); + break; + case 24: + i81x->pixconf |= (6<<16); + break; + case 32: /* not supported */ + i81x->pixconf |= (7<<16); + break; + default: + error("%s: depth %d not supported\n", ctlr->name, vga->mode->z); + } + + /* DON'T CARE of Sequencer Reg. */ + /* DON'T CARE of Attribute registers other than this */ + vga->attribute[0x11] = 0; /* over scancolor = black */ + /* DON't CARE of graphics[1], [2], [3], [4], [5], [6], [7] and [8] value */ + if(vga->linear && (ctlr->flag & Hlinear)) { + /* enable linear mapping, no VGA memory and no page mapping */ + vga->graphics[0x10] = 0x0A; + ctlr->flag |= Ulinear; + } + + vt = vga->mode->vt; + vde = vga->virty; + vrs = vga->mode->vrs; + vre = vga->mode->vre+6; /* shift 7 pixel up */ + + if(vga->mode->interlace == 'v') { + vt /= 2; + vde /= 2; + vrs /= 2; + vre /= 2; + } + /* Reset Row scan */ + vga->crt[8] = 0; +/* Line Compare, bit 6 of crt[9], bit 4 of crt[7] and crt[0x18], should be + * vga->crt[9] = vgaxi(Crtx, 9) | ((vde>>9 & 1)<<6) & 0x7F; + * vga->crt[7] = vgaxi(Crtx, 7) | ((vde>>8 & 1)<<4); + * vga->crt[0x18] = vde & 0xFF; + * However, above values don't work!! I don't know why. K.Okamoto + */ + vga->crt[9] = 0; /* I don't know why ? */ + vga->crt[7] = 0; /* I don't know why ? */ + vga->crt[0x18] = 0; /* I don't know why ? */ +/* 32 bits Start Address of frame buffer (AGP aperture memory) + vga->crt[0x42] = MSB 8 bits of Start Address Register, extended high start address Reg. + vga->crt[0x40] = higer 6 bits in 0~5 bits, and the MSB = 1, extebded start address Reg. + vga->crt[0x0C] = Start Address High Register + vga->crt[0x0D] = Start Address Low Register + LSB 2 bits of Start Address are always 0 + */ + vga->crt[0x42] = vga->pci->mem[0].bar>>24 & 0xFF; + vga->crt[0x40] = vga->pci->mem[0].bar>>18 & 0x3F | 0x80; + /* Start Address High */ + vga->crt[0x0C] = vga->pci->mem[0].bar>>10 & 0xFF; + /* Start Address Low */ + vga->crt[0x0D] = (vga->pci->mem[0].bar >>2 + 1)& 0xFF; + /* Underline Location, Memory Mode, DON'T CARE THIS VALUE */ + vga->crt[0x14] = 0x0; + /* CRT Mode Control */ + vga->crt[0x17] = 0x80; /* CRT normal mode */ + /* Frame buffer memory offset (memory amount for a line) */ + /* vga->crt[0x13] = lower 8 bits of Offset Register + vga->crt[0x41] = MSB 4 bits, those value should be + vga->crt[0x13] = (vga->virtx*(vga->mode->z>>3)/4) & 0xFF; + vga->crt[0x41] = (vga->virtx*(vga->mode->z>>3)/4)>>8 & 0x0F; + However, those doesn't work properly K.Okamoto + */ + vga->crt[0x41] = (vga->crt[0x13]>>8) & 0x0F; //dhog + + /* Horizontal Total */ + vga->crt[0] = ((vga->mode->ht>>3)-6) & 0xFF; + /* Extended Horizontal Total Time Reg (ht) */ + vga->crt[0x35] = vga->mode->ht>>12 & 0x01; +// vga->crt[0x35] = (((vga->mode->ht>>1)-5)>>8) & 0x01; //dhog + /* Horizontal Display Enable End == horizontal width */ + vga->crt[1] = (vga->virtx-1)>>3 & 0xFF; + /* Horizontal Blanking Start */ + vga->crt[2] = ((vga->mode->shb>>3)-1) & 0xFF; + /* Horizontal blanking End crt[39](0),crt[5](7),crt[3](4:0) */ + vga->crt[3] = (vga->mode->shb - vga->virtx)>>3 & 0x1F; + vga->crt[5] = ((vga->mode->shb - vga->virtx)>>3 & 0x20) <<2; + vga->crt[0x39] = ((vga->mode->shb - vga->virtx)>>3 & 0x40) >>6; +// vga->crt[0x39] = (vga->mode->ehb>>9) & 0x01; //dhog + /* Horizontal Sync Start */ + vga->crt[4] = vga->mode->shb>>3 & 0xFF; + /* Horizontal Sync End */ + vga->crt[5] |= vga->mode->ehb>>3 & 0x1F; + /* Extended Vertical Total (vt) */ + vga->crt[6] = (vt - 2) & 0xFF; + vga->crt[0x30] = (vt - 2)>>8 & 0x0F; + /* Vertical Sync Period */ + vga->crt[0x11] = (vre - vrs - 2) & 0x0F; + /* Vertical Blanking End */ + vga->crt[0x16] = (vre - vrs) & 0xFF; + /* Extended Vertical Display End (y) */ + vga->crt[0x12] = (vde-1) & 0xFF; + vga->crt[0x31] = (vde-1)>>8 & 0x0f; + /* Extended Vertical Sync Start (vrs) */ + vga->crt[0x10] = (vrs-1) & 0xFF; + vga->crt[0x32] = (vrs-1)>>8 & 0x0F; + /* Extended Vertical Blanking Start (vrs) */ + vga->crt[0x15] = vrs & 0xFF; + vga->crt[0x33] = vrs>>8 & 0x0F; + + if(vga->mode->interlace == 'v') + vga->crt[0x70] = vrs | 0x80; + else + vga->crt[0x70] = 0; + vga->crt[0x80] = 1; + + ctlr->flag |= Finit; +} + +static void +load(Vga* vga, Ctlr* ctlr) +{ + int i; + ulong *rp; + I81x *i81x; + char *p; + + i81x = vga->private; + + vgaxo(Attrx, 0x11, vga->attribute[0x11]); + /* set the screen graphic mode */ + vgaxo(Crtx, 0x80, vga->crt[0x80]); + vgaxo(Grx, 0x10, vga->graphics[0x10]); + vgao(MiscW, vga->misc); + for(i=0; i <= 0x18; i++) + vgaxo(Crtx, i, vga->crt[i]); + for(i=0x30; i <= 0x82; i++) + vgaxo(Crtx, i, vga->crt[i]); + vga->crt[0x40] |= 0x80; /* set CR40, then set the MSB bit of it */ + vgaxo(Crtx, 0x40, vga->crt[0x40]); + /* 0x06000 = offset of Vertical Clock Devisor VGA0 */ + rp = (ulong*)(i81x->mmio+0x06000); + for(i=0; i < nelem(i81x->clk); i++) + *rp++ = i81x->clk[i]; + rp = (ulong*)(i81x->mmio+0x60000); + for(i = 0; i < nelem(i81x->lcd); i++) + *rp++ = i81x->lcd[i]; + /* set cursor, graphic mode */ + rp = (ulong*)(i81x->mmio+0x70008); + *rp = i81x->pixconf | (1<<8); + + p = (char*)(i81x->mmio+Pixmask); /* DACMASK */ + *p = 0xff; + p = (char*)(i81x->mmio+PaddrW); /* DACWX */ + *p = 0x04; + p = (char*)(i81x->mmio+Pdata); /* DACDATA */ + *p = 0xff; + *p = 0xff; + *p = 0xff; + *p = 0x00; + *p = 0x00; + *p = 0x00; + *rp = i81x->pixconf; + + ctlr->flag |= Fload; +} + +static void +dump(Vga* vga, Ctlr* ctlr) +{ + int i; + Pcidev *p; + I81x *i81x; + char *name; + + name = ctlr->name; + i81x = vga->private; + + printitem(name, "Crt30"); + for(i = 0x30; i <= 0x39; i++) + printreg(vga->crt[i]); + + printitem(name, "Crt40"); + for(i = 0x40; i <= 0x42; i++) + printreg(vga->crt[i]); + + printitem(name, "Crt70"); + for(i = 0x70; i <= 0x79; i++) + printreg(vga->crt[i]); + + printitem(name, "Crt80"); + for(i = 0x80; i <= 0x82; i++) + printreg(vga->crt[i]); + + printitem(name, "Graphics10"); + for(i = 0x10; i <= 0x1f; i++) + printreg(vga->graphics[i]); + + printitem(name, "clk"); + for(i = 0; i < nelem(i81x->clk); i++) + printreg(i81x->clk[i]); + + printitem(name, "lcd"); + for(i = 0; i < nelem(i81x->lcd); i++) + printreg(i81x->lcd[i]); + + printitem(name, "pixconf"); + printreg(i81x->pixconf); + + p = i81x->pci; + printitem(name, "mem[0]"); + Bprint(&stdout, "base %lux size %d\n", p->mem[0].bar & ~0x0F, p->mem[0].size); + + printitem(name, "mem[1]"); + Bprint(&stdout, "base %lux size %d\n", p->mem[1].bar & ~0x0F, p->mem[1].size); + +} + +Ctlr i81x = { + "i81x", /* name */ + snarf, /* snarf */ + options, /* options */ + init, /* init */ + load, /* load */ + dump, /* dump */ +}; + +Ctlr i81xhwgc = { + "i81xhwgc", /* name */ + 0, /* snarf */ + 0, /* options */ + 0, /* init */ + 0, /* load */ + 0, /* dump */ +}; |