From 68d6b0808bbd57a91abf2a5ac4571e4372a8d3fc Mon Sep 17 00:00:00 2001 From: aiju Date: Fri, 15 Apr 2011 20:29:46 +0200 Subject: [PATCH] added geode driver --- lib/vgadb | 21 +++ sys/src/9/pc/devarch.c | 20 +++ sys/src/9/pc/pc | 1 + sys/src/9/pc/vgageode.c | 126 ++++++++++++++++++ sys/src/cmd/aux/vga/data.c | 2 + sys/src/cmd/aux/vga/geode.c | 214 ++++++++++++++++++++++++++++++ sys/src/cmd/aux/vga/geode_modes.h | 65 +++++++++ sys/src/cmd/aux/vga/io.c | 24 ++++ sys/src/cmd/aux/vga/mkfile | 1 + sys/src/cmd/aux/vga/vga.h | 7 + 10 files changed, 481 insertions(+) create mode 100644 sys/src/9/pc/vgageode.c create mode 100644 sys/src/cmd/aux/vga/geode.c create mode 100644 sys/src/cmd/aux/vga/geode_modes.h diff --git a/lib/vgadb b/lib/vgadb index 0181cc0b5..0dd50921a 100755 --- a/lib/vgadb +++ b/lib/vgadb @@ -428,6 +428,12 @@ ctlr ctlr=radeon linear=1 hwgc=radeonhwgc +ctlr + vid=0x1022 did=0x2081 # AMD Geode LX + link=vga + hwgc=geodehwgc + ctlr=geode linear=1 + # # mode: # These entries specify a monitor operating mode. @@ -1631,3 +1637,18 @@ p109b6=1600x1200 # 75Hz # QUXGA 3200x2400 Quad UXGA # QUXGA-W 3840x2400 Wide-QUXGA # + +geode + alias=vga + +geode=1024x768 + defaultclock=65 + shb=1032 ehb=1176 ht=1344 + shs=1056 + vrs=771 vre=777 vt=806 + hsync=- vsync=- + +geode=1280x1024 + defaultclock=108 + shb=1312 ehb=1496 ht=1720 + vrs=1025 vre=1028 vt=1074 diff --git a/sys/src/9/pc/devarch.c b/sys/src/9/pc/devarch.c index bd216c2ad..3228736ee 100644 --- a/sys/src/9/pc/devarch.c +++ b/sys/src/9/pc/devarch.c @@ -33,6 +33,7 @@ enum { Qiob, Qiow, Qiol, + Qmsr, Qbase, Qmax = 16, @@ -55,6 +56,7 @@ static Dirtab archdir[Qmax] = { "iob", { Qiob, 0 }, 0, 0660, "iow", { Qiow, 0 }, 0, 0660, "iol", { Qiol, 0 }, 0, 0660, + "msr", { Qmsr, 0}, 0, 0660, }; Lock archwlock; /* the lock is only for changing archdir */ int narchdir = Qbase; @@ -356,6 +358,7 @@ archread(Chan *c, void *a, long n, vlong offset) int port; ushort *sp; ulong *lp; + vlong *vp; IOMap *m; Rdwrfn *fn; @@ -389,6 +392,14 @@ archread(Chan *c, void *a, long n, vlong offset) *lp++ = inl(port); return n; + case Qmsr: + if(n & 7) + error(Ebadarg); + vp = a; + for(port = offset; port < offset+n; port += 8) + rdmsr(port, vp++); + return n; + case Qioalloc: break; @@ -429,6 +440,7 @@ archwrite(Chan *c, void *a, long n, vlong offset) int port; ushort *sp; ulong *lp; + vlong *vp; Rdwrfn *fn; switch((ulong)c->qid.path){ @@ -458,6 +470,14 @@ archwrite(Chan *c, void *a, long n, vlong offset) outl(port, *lp++); return n; + case Qmsr: + if(n & 7) + error(Ebadarg); + vp = a; + for(port = offset; port < offset+n; port += 8) + wrmsr(port, *vp++); + return n; + default: if(c->qid.path < narchdir && (fn = writefn[c->qid.path])) return fn(c, a, n, offset); diff --git a/sys/src/9/pc/pc b/sys/src/9/pc/pc index d05e60baa..ba897e94a 100644 --- a/sys/src/9/pc/pc +++ b/sys/src/9/pc/pc @@ -108,6 +108,7 @@ misc vgatvp3026 =cur vgavesa vgavmware +cur + vgageode +cur ip tcp diff --git a/sys/src/9/pc/vgageode.c b/sys/src/9/pc/vgageode.c new file mode 100644 index 000000000..513f942ec --- /dev/null +++ b/sys/src/9/pc/vgageode.c @@ -0,0 +1,126 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +#define Image IMAGE +#include +#include +#include +#include "screen.h" + +enum { + DC_UNLOCK = 0, + DC_UNLOCKVALUE = 0x4758, + DC_GENERAL_CFG = 1, + CURE = 2, + DC_CURS_ST_OFFSET = 6, + DC_CURSOR_X = 24, + DC_CURSOR_Y = 25, + DC_PAL_ADDRESS = 28, + DC_PAL_DATA +}; + +static void +geodeenable(VGAscr* scr) +{ + Pcidev *p; + + if(scr->mmio) return; + p = pcimatch(0, 0x1022, 0x2081); + if(!p) return; + scr->mmio = vmap(p->mem[2].bar&~0x0F, p->mem[2].size); + if(!scr->mmio) return; + scr->pci = p; + addvgaseg("geodegp", p->mem[1].bar&~0x0F, p->mem[1].size); + addvgaseg("geodemmio", p->mem[2].bar&~0x0F, p->mem[2].size); + addvgaseg("geodevid", p->mem[3].bar&~0x0F, p->mem[3].size); + vgalinearpci(scr); + if(scr->apsize) + addvgaseg("geodescreen", scr->paddr, scr->apsize); + scr->storage = 0x800000; +} + +static void +geodelinear(VGAscr*, int, int) +{ +} + +static void +geodecurload(VGAscr* scr, Cursor* curs) +{ + uvlong *p, and1, xor1, and2, xor2; + int i; + uchar *c, *s; + + if(!scr->mmio) return; + p = (uvlong*)((uchar*)scr->vaddr + scr->storage); + c = curs->clr; + s = curs->set; + for(i=0;i<16;i++) { + and1 = 0xFF ^ (*s ^ *c++); + xor1 = *s++; + and1 &= ~xor1; + and2 = 0xFF ^ (*s ^ *c++); + xor2 = *s++; + and2 &= ~xor2; + *p++ = (and1 << 56) | (and2 << 48) | 0xFFFFFFFFFFFFLL; + *p++ = (xor1 << 56) | (xor2 << 48); + } + for(;i<128;i++) { + *p++ = -1; + *p++ = 0; + } + scr->offset = curs->offset; +} + +static int +geodecurmove(VGAscr* scr, Point p) { + if(!scr->mmio) return 1; + ((ulong*)scr->mmio)[DC_UNLOCK] = DC_UNLOCKVALUE; + ((ulong*)scr->mmio)[DC_CURSOR_X] = p.x + scr->offset.x; + ((ulong*)scr->mmio)[DC_CURSOR_Y] = p.y + scr->offset.y; + return 0; +} + +static void +geodecurenable(VGAscr* scr) +{ + geodeenable(scr); + if(!scr->mmio) return; + geodecurload(scr, &arrow); + geodecurmove(scr, ZP); + ((ulong*)scr->mmio)[DC_UNLOCK] = DC_UNLOCKVALUE; + ((ulong*)scr->mmio)[DC_CURS_ST_OFFSET] = scr->storage; + ((ulong*)scr->mmio)[DC_GENERAL_CFG] |= CURE; + /* set cursor colours */ + ((ulong*)scr->mmio)[DC_PAL_ADDRESS] = 0x100; + ((ulong*)scr->mmio)[DC_PAL_DATA] = -1; + ((ulong*)scr->mmio)[DC_PAL_DATA] = 0; +} + +static void +geodecurdisable(VGAscr* scr) +{ + if(!scr->mmio) return; + ((ulong*)scr->mmio)[DC_UNLOCK] = DC_UNLOCKVALUE; + ((ulong*)scr->mmio)[DC_GENERAL_CFG] &= ~CURE; +} + +VGAdev vgageodedev = { + "geode", + geodeenable, + .linear = geodelinear, +}; + + +VGAcur vgageodecur = { + "geodehwgc", + geodecurenable, + geodecurdisable, + geodecurload, + geodecurmove, +}; diff --git a/sys/src/cmd/aux/vga/data.c b/sys/src/cmd/aux/vga/data.c index 52da2ef91..1d97534eb 100644 --- a/sys/src/cmd/aux/vga/data.c +++ b/sys/src/cmd/aux/vga/data.c @@ -30,6 +30,8 @@ Ctlr* ctlrs[] = { &et4000, /* ctlr */ &et4000hwgc, /* hwgc */ &generic, /* ctlr */ + &geode, /* ctlr */ + &geodehwgc, /* hwgc */ &hiqvideo, /* ctlr */ &hiqvideohwgc, /* hwgc */ &i81x, /* ctlr */ diff --git a/sys/src/cmd/aux/vga/geode.c b/sys/src/cmd/aux/vga/geode.c new file mode 100644 index 000000000..6bae51b68 --- /dev/null +++ b/sys/src/cmd/aux/vga/geode.c @@ -0,0 +1,214 @@ +#include +#include +#include + +#include "pci.h" +#include "vga.h" + +#include "geode_modes.h" + +enum { + Nregs = 28, + DC_UNLOCK = 0, + DC_GENERAL_CFG, + DC_DISPLAY_CFG, + DC_ARB_CFG, + DC_H_ACTIVE_TIMING = 16, + DC_H_BLANK_TIMING, + DC_H_SYNC_TIMING, + DC_V_ACTIVE_TIMING = 20, + DC_V_BLANK_TIMING, + DC_V_SYNC_TIMING, + DC_FB_ACTIVE, + DC_LINE_SIZE = 12, + DC_GFX_PITCH, + + DC_UNLOCK_VALUE = 0x4758, + + /* DC_GENERAL_CFG */ + VGAE = 1<<7, /* VGA enable */ + DFLE = 1, /* display FIFO enable */ + + /* DC_DISPLAY_CFG */ + TGEN = 1, /* timing enable */ + GDEN = 1<<3, /* graphics enable */ + VDEN = 1<<4, /* video enable */ + TRUP = 1<<6, /* timing register update */ + PALB = 1<<25, /* palette bypass */ + DISP_MODE8 = 0, + DISP_MODE16 = 1<<8, + DISP_MODE24 = 1<<9, + DISP_MODE32 = (1<<8) | (1<<9), + + /* low bandwidth */ + LBW_GENERAL = 0x9500, + LBW_DISPLAY = 0x8000, + LBW_ARB = 0x150001, + /* average bandwidth */ + ABW_GENERAL = 0xB600, + ABW_DISPLAY = 0x9000, + ABW_ARB = 0x160001, +}; + +typedef struct Geode Geode; +struct Geode { + ulong *mmio; + Pcidev *pci; + ulong regs[Nregs]; + uvlong clock; +}; + +static void +snarf(Vga* vga, Ctlr* ctlr) +{ + Geode *geode; + int i; + + if(!vga->private) { + geode = alloc(sizeof(Geode)); + geode->pci = pcimatch(0, 0x1022, 0x2081); + if(!geode->pci) error("%s: not found\n", ctlr->name); + vgactlw("type", "geode"); + geode->mmio = segattach(0, "geodemmio", 0, geode->pci->mem[2].size); + if(geode->mmio == (ulong*)-1) error("%s: can't attach mmio segment\n", ctlr->name); + vga->private = geode; + } + else geode = vga->private; + + for(i=0;iregs[i] = geode->mmio[i]; + geode->clock = rdmsr(0x4C000015); + + vga->crt[43] = vgaxi(Crtx, 43); + vga->crt[44] = vgaxi(Crtx, 44); + vga->crt[47] = vgaxi(Crtx, 47); + vga->crt[48] = vgaxi(Crtx, 48); + ctlr->flag |= Fsnarf; +} + +static void +options(Vga* vga, Ctlr* ctlr) +{ + USED(vga); + ctlr->flag |= Foptions; +} + +static void +init(Vga* vga, Ctlr* ctlr) +{ + Geode *geode; + Mode *m; + int i, bpp; + + geode = vga->private; + m = vga->mode; + m->vbs = m->vrs; + m->vbe = m->vre; + + + /* there has to be a better solution */ + if(m->x < 1024) { + geode->regs[DC_GENERAL_CFG] = LBW_GENERAL; + geode->regs[DC_DISPLAY_CFG] = LBW_DISPLAY; + geode->regs[DC_ARB_CFG] = LBW_ARB; + } else { + geode->regs[DC_GENERAL_CFG] = ABW_GENERAL; + geode->regs[DC_DISPLAY_CFG] = ABW_DISPLAY; + geode->regs[DC_ARB_CFG] = ABW_ARB; + } + + geode->regs[DC_GENERAL_CFG] |= DFLE; + geode->regs[DC_DISPLAY_CFG] |= GDEN | VDEN | TGEN | TRUP | PALB; + + switch(m->z) { + case 8: bpp = 1; break; + case 15: case 16: bpp = 2; geode->regs[DC_DISPLAY_CFG] |= DISP_MODE16; break; + case 24: bpp = 3; geode->regs[DC_DISPLAY_CFG] |= DISP_MODE24; break; + case 32: bpp = 4; geode->regs[DC_DISPLAY_CFG] |= DISP_MODE32; break; + default: error("%s: unknown bpp value\n", ctlr->name); bpp = 0; + } + + geode->regs[DC_H_ACTIVE_TIMING] = (m->x - 1) | ((m->ht - 1) << 16); + geode->regs[DC_H_BLANK_TIMING] = (m->shb - 1) | ((m->ehb - 1) << 16); + geode->regs[DC_H_SYNC_TIMING] = (m->shs - 1) | ((m->ehs - 1) << 16); + geode->regs[DC_V_ACTIVE_TIMING] = (m->y - 1) | ((m->vt - 1) << 16); + geode->regs[DC_V_BLANK_TIMING] = (m->vrs - 1) | ((m->vre - 1) << 16); + geode->regs[DC_V_SYNC_TIMING] = (m->vbs - 1) | ((m->vbe - 1) << 16); + geode->regs[DC_FB_ACTIVE] = (m->x - 1) | ((m->y - 1) << 16); + geode->regs[DC_GFX_PITCH] = geode->regs[DC_LINE_SIZE] = (m->x >> 3) * bpp; + + for(i=0;ifrequency) + goto modefound; + error("%s: unknown clock value\n", ctlr->name); +modefound: + geode->clock = ((uvlong)geode_modes[i][0] << 32); + + ctlr->flag |= Finit; +} + +static void +load(Vga* vga, Ctlr* ctlr) +{ + Geode *geode; + int i; + + geode = vga->private; + wrmsr(0x4C000015, geode->clock); + geode->mmio[DC_UNLOCK] = DC_UNLOCK_VALUE; + for(i=4;immio[i] = geode->regs[i]; + for(i=1;i<4;i++) geode->mmio[i] = geode->regs[i]; + ctlr->flag |= Fload; +} + +static void +printreg32(ulong u) { + printreg((u>>24)&0xFF); + printreg((u>>16)&0xFF); + printreg((u>>8)&0xFF); + printreg(u&0xFF); +} + +static void +dump(Vga* vga, Ctlr* ctlr) +{ + int i; + Geode *geode; + + geode = vga->private; + printitem(ctlr->name, "configuration"); + for(i=0;i<4;i++) printreg32(geode->regs[i]); + printitem(ctlr->name, "memory"); + for(i=4;i<15;i++) printreg32(geode->regs[i]); + printitem(ctlr->name, "timing"); + for(i=16;i<24;i++) printreg32(geode->regs[i]); + printitem(ctlr->name, "cursor"); + for(i=24;i<28;i++) printreg32(geode->regs[i]); + + printitem(ctlr->name, "ext"); + printreg(vga->crt[43]); + printreg(vga->crt[44]); + printreg(vga->crt[47]); + printreg(vga->crt[48]); + + printitem(ctlr->name, "clock"); + printreg32((geode->clock >> 32) & 0xFFFFFFFF); + printreg32(geode->clock & 0xFFFFFFFF); +} + +Ctlr geode = { + "geode", /* name */ + snarf, /* snarf */ + options, /* options */ + init, /* init */ + load, /* load */ + dump, /* dump */ +}; + +Ctlr geodehwgc = { + "geodehwgc", + 0, + 0, + 0, + 0, + 0, +}; \ No newline at end of file diff --git a/sys/src/cmd/aux/vga/geode_modes.h b/sys/src/cmd/aux/vga/geode_modes.h new file mode 100644 index 000000000..b6274dab6 --- /dev/null +++ b/sys/src/cmd/aux/vga/geode_modes.h @@ -0,0 +1,65 @@ +enum {NumModes = 61}; + +static const ulong geode_modes[NumModes][2] = { +{0x000031AC, 24923000}, +{0x0000215D, 25175000}, +{0x00001087, 27000000}, +{0x0000216C, 28322000}, +{0x0000218D, 28560000}, +{0x000010C9, 31200000}, +{0x00003147, 31500000}, +{0x000010A7, 33032000}, +{0x00002159, 35112000}, +{0x00004249, 35500000}, +{0x00000057, 36000000}, +{0x0000219A, 37889000}, +{0x00002158, 39168000}, +{0x00000045, 40000000}, +{0x00000089, 43163000}, +{0x000010E7, 44900000}, +{0x00002136, 45720000}, +{0x00003207, 49500000}, +{0x00002187, 50000000}, +{0x00004286, 56250000}, +{0x000010E5, 60065000}, +{0x00004214, 65000000}, +{0x00001105, 68179000}, +{0x000031E4, 74250000}, +{0x00003183, 75000000}, +{0x00004284, 78750000}, +{0x00001104, 81600000}, +{0x00006363, 94500000}, +{0x00005303, 97520000}, +{0x00002183, 100187000}, +{0x00002122, 101420000}, +{0x000041B1, 106500000}, +{0x00001081, 108000000}, +{0x00006201, 113310000}, +{0x00000041, 119650000}, +{0x000041A1, 129600000}, +{0x00002182, 133500000}, +{0x000041B1, 135000000}, +{0x00000051, 144000000}, +{0x000041E1, 148500000}, +{0x000062D1, 157500000}, +{0x000031A1, 162000000}, +{0x00000061, 169203000}, +{0x00004231, 172800000}, +{0x00002151, 175500000}, +{0x000052E1, 189000000}, +{0x00000071, 192000000}, +{0x00003201, 198000000}, +{0x00004291, 202500000}, +{0x00001101, 204750000}, +{0x00007481, 218250000}, +{0x00004170, 229500000}, +{0x00006210, 234000000}, +{0x00003140, 251182000}, +{0x00006250, 261000000}, +{0x000041C0, 278400000}, +{0x00005220, 280640000}, +{0x00000050, 288000000}, +{0x000041E0, 297000000}, +{0x00002130, 320207000}, +{0x00006310, 341349000}, +}; diff --git a/sys/src/cmd/aux/vga/io.c b/sys/src/cmd/aux/vga/io.c index c602c0837..ed73f6a27 100644 --- a/sys/src/cmd/aux/vga/io.c +++ b/sys/src/cmd/aux/vga/io.c @@ -11,6 +11,7 @@ static int iobfd = -1; static int iowfd = -1; static int iolfd = -1; static int biosfd = -1; +static int msrfd = -1; static ulong biosoffset = 0; enum { @@ -106,6 +107,29 @@ outportl(long port, ulong data) error("outportl(0x%4.4lx, 0x%2.2luX): %r\n", port, data); } +uvlong +rdmsr(long port) +{ + uvlong data; + + if(msrfd == -1) + msrfd = devopen("#P/msr", ORDWR); + + if(pread(msrfd, &data, sizeof(data), port) != sizeof(data)) + error("rdmsr(0x%4.4lx): %r\n", port); + return data; +} + +void +wrmsr(long port, uvlong data) +{ + if(msrfd == -1) + msrfd = devopen("#P/msr", ORDWR); + + if(pwrite(msrfd, &data, sizeof(data), port) != sizeof(data)) + error("wrmsr(0x%4.4lx, 0x%2.2lluX): %r\n", port, data); +} + static void vgactlinit(void) { diff --git a/sys/src/cmd/aux/vga/mkfile b/sys/src/cmd/aux/vga/mkfile index ee4769c17..ce05eed4f 100644 --- a/sys/src/cmd/aux/vga/mkfile +++ b/sys/src/cmd/aux/vga/mkfile @@ -25,6 +25,7 @@ OFILES=\ ics2494.$O\ ics534x.$O\ io.$O\ + geode.$O\ mach32.$O\ mach64.$O\ mach64xx.$O\ diff --git a/sys/src/cmd/aux/vga/vga.h b/sys/src/cmd/aux/vga/vga.h index 832b4fac1..b6b6a9d20 100644 --- a/sys/src/cmd/aux/vga/vga.h +++ b/sys/src/cmd/aux/vga/vga.h @@ -302,6 +302,13 @@ extern void printreg(ulong); extern void printflag(ulong); extern void setpalette(int, int, int, int); extern int curprintindex; +extern uvlong rdmsr(long); +extern void wrmsr(long, uvlong); + +/* geode.c */ + +extern Ctlr geode; +extern Ctlr geodehwgc; /* mach32.c */ extern Ctlr mach32;