shithub: riscv

Download patch

ref: 68d6b0808bbd57a91abf2a5ac4571e4372a8d3fc
parent: a95f7282410ebfa4e2a4ff816e8486e7e0f8284a
author: aiju <devnull@localhost>
date: Fri Apr 15 16:29:46 EDT 2011

added geode driver

--- a/lib/vgadb
+++ b/lib/vgadb
@@ -428,6 +428,12 @@
 	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 @@
 # 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
--- a/sys/src/9/pc/devarch.c
+++ b/sys/src/9/pc/devarch.c
@@ -33,6 +33,7 @@
 	Qiob,
 	Qiow,
 	Qiol,
+	Qmsr,
 	Qbase,
 
 	Qmax = 16,
@@ -55,6 +56,7 @@
 	"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 @@
 	int port;
 	ushort *sp;
 	ulong *lp;
+	vlong *vp;
 	IOMap *m;
 	Rdwrfn *fn;
 
@@ -389,6 +392,14 @@
 			*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 @@
 	int port;
 	ushort *sp;
 	ulong *lp;
+	vlong *vp;
 	Rdwrfn *fn;
 
 	switch((ulong)c->qid.path){
@@ -456,6 +468,14 @@
 		lp = a;
 		for(port = offset; port < offset+n; port += 4)
 			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:
--- a/sys/src/9/pc/pc
+++ b/sys/src/9/pc/pc
@@ -108,6 +108,7 @@
 	vgatvp3026	=cur
 	vgavesa
 	vgavmware	+cur
+	vgageode	+cur
 
 ip
 	tcp
--- /dev/null
+++ b/sys/src/9/pc/vgageode.c
@@ -1,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 <draw.h>
+#include <memdraw.h>
+#include <cursor.h>
+#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,
+};
--- a/sys/src/cmd/aux/vga/data.c
+++ b/sys/src/cmd/aux/vga/data.c
@@ -30,6 +30,8 @@
 	&et4000,				/* ctlr */
 	&et4000hwgc,				/* hwgc */
 	&generic,				/* ctlr */
+	&geode,				/* ctlr */
+	&geodehwgc,			/* hwgc */
 	&hiqvideo,				/* ctlr */
 	&hiqvideohwgc,				/* hwgc */
 	&i81x,				/* ctlr */
--- /dev/null
+++ b/sys/src/cmd/aux/vga/geode.c
@@ -1,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
--- /dev/null
+++ b/sys/src/cmd/aux/vga/geode_modes.h
@@ -1,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},
+};
--- a/sys/src/cmd/aux/vga/io.c
+++ b/sys/src/cmd/aux/vga/io.c
@@ -11,6 +11,7 @@
 static int iowfd = -1;
 static int iolfd = -1;
 static int biosfd = -1;
+static int msrfd = -1;
 static ulong biosoffset = 0;
 
 enum {
@@ -104,6 +105,29 @@
 
 	if(pwrite(iolfd, &data, sizeof(data), port) != sizeof(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
--- a/sys/src/cmd/aux/vga/mkfile
+++ b/sys/src/cmd/aux/vga/mkfile
@@ -25,6 +25,7 @@
 	ics2494.$O\
 	ics534x.$O\
 	io.$O\
+	geode.$O\
 	mach32.$O\
 	mach64.$O\
 	mach64xx.$O\
--- a/sys/src/cmd/aux/vga/vga.h
+++ b/sys/src/cmd/aux/vga/vga.h
@@ -302,6 +302,13 @@
 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;