diff options
author | aiju <devnull@localhost> | 2011-04-15 20:29:46 +0200 |
---|---|---|
committer | aiju <devnull@localhost> | 2011-04-15 20:29:46 +0200 |
commit | 68d6b0808bbd57a91abf2a5ac4571e4372a8d3fc (patch) | |
tree | 4b0b6214de9c0e70fc26d09264c41557f1f23510 /sys/src/cmd/aux/vga/geode.c | |
parent | a95f7282410ebfa4e2a4ff816e8486e7e0f8284a (diff) |
added geode driver
Diffstat (limited to 'sys/src/cmd/aux/vga/geode.c')
-rw-r--r-- | sys/src/cmd/aux/vga/geode.c | 214 |
1 files changed, 214 insertions, 0 deletions
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 <u.h> +#include <libc.h> +#include <bio.h> + +#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;i<Nregs;i++) geode->regs[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;i<NumModes;i++) + if(geode_modes[i][1] == m->frequency) + 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;i<Nregs;i++) geode->mmio[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 |