summaryrefslogtreecommitdiff
path: root/sys/src/cmd/aux/vga/geode.c
diff options
context:
space:
mode:
authoraiju <devnull@localhost>2011-04-15 20:29:46 +0200
committeraiju <devnull@localhost>2011-04-15 20:29:46 +0200
commit68d6b0808bbd57a91abf2a5ac4571e4372a8d3fc (patch)
tree4b0b6214de9c0e70fc26d09264c41557f1f23510 /sys/src/cmd/aux/vga/geode.c
parenta95f7282410ebfa4e2a4ff816e8486e7e0f8284a (diff)
added geode driver
Diffstat (limited to 'sys/src/cmd/aux/vga/geode.c')
-rw-r--r--sys/src/cmd/aux/vga/geode.c214
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