ref: 2aec1f8a09ae0bc9fb269d84ef53defebc47eede
dir: /sys/src/cmd/aux/vga/geode.c/
#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 = vga->pci; if(geode->pci == nil){ geode->pci = pcimatch(0, 0x1022, 0x2081); if(!geode->pci) error("%s: not found\n", ctlr->name); } vgactlpci(geode->pci); 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; /* 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->vrs - 1) | ((m->vre - 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, };