summaryrefslogtreecommitdiff
path: root/sys/src/9/pc/vgaradeon.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/pc/vgaradeon.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/pc/vgaradeon.c')
-rwxr-xr-xsys/src/9/pc/vgaradeon.c520
1 files changed, 520 insertions, 0 deletions
diff --git a/sys/src/9/pc/vgaradeon.c b/sys/src/9/pc/vgaradeon.c
new file mode 100755
index 000000000..6fb89c8da
--- /dev/null
+++ b/sys/src/9/pc/vgaradeon.c
@@ -0,0 +1,520 @@
+/*
+ * ATI Radeon [789]XXX vga driver
+ * see /sys/src/cmd/aux/vga/radeon.c
+ */
+#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"
+
+#include "/sys/src/cmd/aux/vga/radeon.h" /* ugh */
+
+/* #define HW_ACCEL */
+
+enum {
+ Kilo = 1024,
+ Meg = Kilo * Kilo,
+};
+
+static Pcidev*
+radeonpci(void)
+{
+ static Pcidev *p = nil;
+ struct pciids *ids;
+
+ while ((p = pcimatch(p, ATI_PCIVID, 0)) != nil)
+ for (ids = radeon_pciids; ids->did; ids++)
+ if (ids->did == p->did)
+ return p;
+ return nil;
+}
+
+/* mmio access */
+
+static void
+OUTREG8(ulong mmio, ulong offset, uchar val)
+{
+ ((uchar*)KADDR((mmio + offset)))[0] = val;
+}
+
+static void
+OUTREG(ulong mmio, ulong offset, ulong val)
+{
+ ((ulong*)KADDR((mmio + offset)))[0] = val;
+}
+
+static ulong
+INREG(ulong mmio, ulong offset)
+{
+ return ((ulong*)KADDR((mmio + offset)))[0];
+}
+
+static void
+OUTREGP(ulong mmio, ulong offset, ulong val, ulong mask)
+{
+ OUTREG(mmio, offset, (INREG(mmio, offset) & mask) | val);
+}
+
+static void
+OUTPLL(ulong mmio, ulong offset, ulong val)
+{
+ OUTREG8(mmio, CLOCK_CNTL_INDEX, (offset & 0x3f) | PLL_WR_EN);
+ OUTREG(mmio, CLOCK_CNTL_DATA, val);
+}
+
+static ulong
+INPLL(ulong mmio, ulong offset)
+{
+ OUTREG8(mmio, CLOCK_CNTL_INDEX, offset & 0x3f);
+ return INREG(mmio, CLOCK_CNTL_DATA);
+}
+
+static void
+OUTPLLP(ulong mmio, ulong offset, ulong val, ulong mask)
+{
+ OUTPLL(mmio, offset, (INPLL(mmio, offset) & mask) | val);
+}
+
+static void
+radeonlinear(VGAscr *, int, int)
+{
+}
+
+static void
+radeonenable(VGAscr *scr)
+{
+ Pcidev *p;
+
+ if (scr->mmio)
+ return;
+ p = radeonpci();
+ if (p == nil)
+ return;
+ scr->id = p->did;
+ scr->pci = p;
+
+ scr->mmio = vmap(p->mem[2].bar & ~0x0f, p->mem[2].size);
+ if(scr->mmio == 0)
+ return;
+ addvgaseg("radeonmmio", p->mem[2].bar & ~0x0f, p->mem[2].size);
+
+ vgalinearpci(scr);
+ if(scr->apsize)
+ addvgaseg("radeonscreen", scr->paddr, scr->apsize);
+}
+
+static void
+radeoncurload(VGAscr *scr, Cursor *curs)
+{
+ int x, y;
+ ulong *p;
+
+ if(scr->mmio == nil)
+ return;
+
+ p = (ulong*)KADDR(scr->storage);
+
+ for(y = 0; y < 64; y++){
+ int cv, sv;
+
+ if (y < 16) {
+ cv = curs->clr[2*y] << 8 | curs->clr[2*y+1];
+ sv = curs->set[2*y] << 8 | curs->set[2*y+1];
+ } else
+ cv = sv = 0;
+
+ for(x = 0; x < 64; x++){
+ ulong col = 0;
+ int c, s;
+
+ if (x < 16) {
+ c = (cv >> (15 - x)) & 1;
+ s = (sv >> (15 - x)) & 1;
+ } else
+ c = s = 0;
+
+ switch(c | s<<1) {
+ case 0:
+ col = 0;
+ break;
+ case 1:
+ col = ~0ul; /* white */
+ break;
+ case 2:
+ case 3:
+ col = 0xff000000; /* black */
+ break;
+ }
+
+ *p++ = col;
+ }
+ }
+
+ scr->offset.x = curs->offset.x;
+ scr->offset.y = curs->offset.y;
+}
+
+static int
+radeoncurmove(VGAscr *scr, Point p)
+{
+ int x, y, ox, oy;
+ static ulong storage = 0;
+
+ if(scr->mmio == nil)
+ return 1;
+
+ if (storage == 0)
+ storage = scr->apsize - 1*Meg;
+
+ x = p.x + scr->offset.x;
+ y = p.y + scr->offset.y;
+ ox = oy = 0;
+
+ if (x < 0) {
+ ox = -x - 1;
+ x = 0;
+ }
+ if (y < 0) {
+ oy = -y - 1;
+ y = 0;
+ }
+
+ OUTREG((ulong)scr->mmio, CUR_OFFSET, storage + oy * 256);
+ OUTREG((ulong)scr->mmio, CUR_HORZ_VERT_OFF,
+ (ox & 0x7fff) << 16 | (oy & 0x7fff));
+ OUTREG((ulong)scr->mmio, CUR_HORZ_VERT_POSN,
+ (x & 0x7fff) << 16 | (y & 0x7fff));
+ return 0;
+}
+
+static void
+radeoncurdisable(VGAscr *scr)
+{
+ if(scr->mmio == nil)
+ return;
+ OUTREGP((ulong)scr->mmio, CRTC_GEN_CNTL, 0, ~CRTC_CUR_EN);
+}
+
+static void
+radeoncurenable(VGAscr *scr)
+{
+ ulong storage;
+
+ if(scr->mmio == 0)
+ return;
+
+ radeoncurdisable(scr);
+ storage = scr->apsize - 1*Meg;
+ scr->storage = (ulong)KADDR(scr->paddr + storage);
+ radeoncurload(scr, &arrow);
+ radeoncurmove(scr, ZP);
+
+ OUTREGP((ulong)scr->mmio, CRTC_GEN_CNTL, CRTC_CUR_EN | 2<<20,
+ ~(CRTC_CUR_EN | 3<<20));
+}
+
+/* hw blank */
+
+static void
+radeonblank(VGAscr* scr, int blank)
+{
+ ulong mask;
+ char *cp;
+
+ if (scr->mmio == 0)
+ return;
+
+// iprint("radeon: hwblank(%d)\n", blank);
+
+ mask = CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS | CRTC_VSYNC_DIS;
+ if (blank == 0) {
+ OUTREGP((ulong)scr->mmio, CRTC_EXT_CNTL, 0, ~mask);
+ return;
+ }
+
+ cp = getconf("*dpms");
+ if (cp) {
+ if (strcmp(cp, "standby") == 0)
+ OUTREGP((ulong)scr->mmio, CRTC_EXT_CNTL,
+ CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS, ~mask);
+ else if (strcmp(cp, "suspend") == 0)
+ OUTREGP((ulong)scr->mmio, CRTC_EXT_CNTL,
+ CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS, ~mask);
+ else if (strcmp(cp, "off") == 0)
+ OUTREGP((ulong)scr->mmio, CRTC_EXT_CNTL, mask, ~mask);
+ return;
+ }
+
+ OUTREGP((ulong)scr->mmio, CRTC_EXT_CNTL, mask, ~mask);
+}
+
+/* hw acceleration */
+
+static void
+radeonwaitfifo(VGAscr *scr, int entries)
+{
+ int i;
+
+ for (i = 0; i < 2000000; i++)
+ if (INREG((ulong)scr->mmio, RBBM_STATUS) & RBBM_FIFOCNT_MASK >=
+ entries)
+ return;
+ iprint("radeon: fifo timeout\n");
+}
+
+static void
+radeonwaitidle(VGAscr *scr)
+{
+ radeonwaitfifo(scr, 64);
+
+ for (; ; ) {
+ int i;
+
+ for (i = 0; i < 2000000; i++)
+ if (!(INREG((ulong)scr->mmio, RBBM_STATUS) & RBBM_ACTIVE))
+ return;
+
+ iprint("radeon: idle timed out: %uld entries, stat=0x%.8ulx\n",
+ INREG((ulong)scr->mmio, RBBM_STATUS) & RBBM_FIFOCNT_MASK,
+ INREG((ulong)scr->mmio, RBBM_STATUS));
+ }
+}
+
+static ulong dp_gui_master_cntl = 0;
+
+static int
+radeonfill(VGAscr *scr, Rectangle r, ulong color)
+{
+ if (scr->mmio == nil)
+ return 0;
+
+ radeonwaitfifo(scr, 6);
+ OUTREG((ulong)scr->mmio, DP_GUI_MASTER_CNTL,
+ dp_gui_master_cntl | GMC_BRUSH_SOLID_COLOR |
+ GMC_SRC_DATATYPE_COLOR | ROP3_P);
+ OUTREG((ulong)scr->mmio, DP_BRUSH_FRGD_CLR, color);
+ OUTREG((ulong)scr->mmio, DP_WRITE_MASK, ~0ul);
+ OUTREG((ulong)scr->mmio, DP_CNTL,
+ DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
+ OUTREG((ulong)scr->mmio, DST_Y_X, r.min.y << 16 | r.min.x);
+ OUTREG((ulong)scr->mmio, DST_WIDTH_HEIGHT, Dx(r) << 16 | Dy(r));
+
+ radeonwaitidle(scr);
+ return 1;
+}
+
+static int
+radeonscroll(VGAscr*scr, Rectangle dst, Rectangle src)
+{
+ int xs, ys, xd, yd, w, h;
+ ulong dp_cntl = 0x20;
+
+ if (scr->mmio == nil)
+ return 0;
+
+ // iprint("radeon: hwscroll(dst:%R, src:%R)\n", dst, src);
+
+ xd = dst.min.x;
+ yd = dst.min.y;
+ xs = src.min.x;
+ ys = src.min.y;
+ w = Dx(dst);
+ h = Dy(dst);
+
+ if (ys < yd) {
+ ys += h - 1;
+ yd += h - 1;
+ } else
+ dp_cntl |= DST_Y_TOP_TO_BOTTOM;
+
+ if (xs < xd) {
+ xs += w - 1;
+ xd += w - 1;
+ } else
+ dp_cntl |= DST_X_LEFT_TO_RIGHT;
+
+ radeonwaitfifo(scr, 6);
+ OUTREG((ulong)scr->mmio, DP_GUI_MASTER_CNTL, dp_gui_master_cntl |
+ GMC_BRUSH_NONE | GMC_SRC_DATATYPE_COLOR | DP_SRC_SOURCE_MEMORY |
+ ROP3_S);
+ OUTREG((ulong)scr->mmio, DP_WRITE_MASK, ~0ul);
+ OUTREG((ulong)scr->mmio, DP_CNTL, dp_cntl);
+ OUTREG((ulong)scr->mmio, SRC_Y_X, ys << 16 | xs);
+ OUTREG((ulong)scr->mmio, DST_Y_X, yd << 16 | xd);
+ OUTREG((ulong)scr->mmio, DST_WIDTH_HEIGHT, w << 16 | h);
+
+ radeonwaitidle(scr);
+
+ // iprint("radeon: hwscroll(xs=%d ys=%d xd=%d yd=%d w=%d h=%d)\n",
+ // xs, ys, xd, yd, w, h);
+ return 1;
+}
+
+static void
+radeondrawinit(VGAscr*scr)
+{
+ ulong bpp, dtype, i, pitch, clock_cntl_index, mclk_cntl, rbbm_soft_reset;
+
+ if (scr->mmio == 0)
+ return;
+
+ switch (scr->gscreen->depth) {
+ case 6:
+ case 8:
+ dtype = 2;
+ bpp = 1;
+ break;
+ case 15:
+ dtype = 3;
+ bpp = 2;
+ break;
+ case 16:
+ dtype = 4;
+ bpp = 2;
+ break;
+ case 32:
+ dtype = 6;
+ bpp = 4;
+ break;
+ default:
+ return;
+ }
+
+ /* disable 3D */
+ OUTREG((ulong)scr->mmio, RB3D_CNTL, 0);
+
+ /* flush engine */
+ OUTREGP((ulong)scr->mmio, RB2D_DSTCACHE_CTLSTAT,
+ RB2D_DC_FLUSH_ALL, ~RB2D_DC_FLUSH_ALL);
+ for (i = 0; i < 2000000; i++)
+ if (!(INREG((ulong)scr->mmio, RB2D_DSTCACHE_CTLSTAT) &
+ RB2D_DC_BUSY))
+ break;
+
+ /* reset 2D engine */
+ clock_cntl_index = INREG((ulong)scr->mmio, CLOCK_CNTL_INDEX);
+
+ mclk_cntl = INPLL((ulong)scr->mmio, MCLK_CNTL);
+ OUTPLL((ulong)scr->mmio, MCLK_CNTL, mclk_cntl | FORCEON_MCLKA |
+ FORCEON_MCLKB | FORCEON_YCLKA | FORCEON_YCLKB | FORCEON_MC |
+ FORCEON_AIC);
+ rbbm_soft_reset = INREG((ulong)scr->mmio, RBBM_SOFT_RESET);
+
+ OUTREG((ulong)scr->mmio, RBBM_SOFT_RESET, rbbm_soft_reset |
+ SOFT_RESET_CP | SOFT_RESET_HI | SOFT_RESET_SE | SOFT_RESET_RE |
+ SOFT_RESET_PP | SOFT_RESET_E2 | SOFT_RESET_RB);
+ INREG((ulong)scr->mmio, RBBM_SOFT_RESET);
+ OUTREG((ulong)scr->mmio, RBBM_SOFT_RESET, rbbm_soft_reset &
+ ~(SOFT_RESET_CP | SOFT_RESET_HI | SOFT_RESET_SE | SOFT_RESET_RE |
+ SOFT_RESET_PP | SOFT_RESET_E2 | SOFT_RESET_RB));
+ INREG((ulong)scr->mmio, RBBM_SOFT_RESET);
+
+ OUTPLL((ulong)scr->mmio, MCLK_CNTL, mclk_cntl);
+ OUTREG((ulong)scr->mmio, CLOCK_CNTL_INDEX, clock_cntl_index);
+
+ /* init 2D engine */
+ radeonwaitfifo(scr, 1);
+ OUTREG((ulong)scr->mmio, RB2D_DSTCACHE_MODE, 0);
+
+ pitch = Dx(scr->gscreen->r) * bpp;
+ radeonwaitfifo(scr, 4);
+ OUTREG((ulong)scr->mmio, DEFAULT_PITCH, pitch);
+ OUTREG((ulong)scr->mmio, DST_PITCH, pitch);
+ OUTREG((ulong)scr->mmio, SRC_PITCH, pitch);
+ OUTREG((ulong)scr->mmio, DST_PITCH_OFFSET_C, 0);
+
+ radeonwaitfifo(scr, 3);
+ OUTREG((ulong)scr->mmio, DEFAULT_OFFSET, 0);
+ OUTREG((ulong)scr->mmio, DST_OFFSET, 0);
+ OUTREG((ulong)scr->mmio, SRC_OFFSET, 0);
+
+ radeonwaitfifo(scr, 1);
+ OUTREGP((ulong)scr->mmio, DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN);
+
+ radeonwaitfifo(scr, 1);
+ OUTREG((ulong)scr->mmio, DEFAULT_SC_BOTTOM_RIGHT,
+ DEFAULT_SC_RIGHT_MAX | DEFAULT_SC_BOTTOM_MAX);
+
+ dp_gui_master_cntl = dtype << GMC_DST_DATATYPE_SHIFT |
+ GMC_SRC_PITCH_OFFSET_CNTL | GMC_DST_PITCH_OFFSET_CNTL |
+ GMC_CLR_CMP_CNTL_DIS;
+ radeonwaitfifo(scr, 1);
+ OUTREG((ulong)scr->mmio, DP_GUI_MASTER_CNTL,
+ dp_gui_master_cntl | GMC_BRUSH_SOLID_COLOR | GMC_SRC_DATATYPE_COLOR);
+
+ radeonwaitfifo(scr, 7);
+ OUTREG((ulong)scr->mmio, DST_LINE_START, 0);
+ OUTREG((ulong)scr->mmio, DST_LINE_END, 0);
+ OUTREG((ulong)scr->mmio, DP_BRUSH_FRGD_CLR, ~0ul);
+ OUTREG((ulong)scr->mmio, DP_BRUSH_BKGD_CLR, 0);
+ OUTREG((ulong)scr->mmio, DP_SRC_FRGD_CLR, ~0ul);
+ OUTREG((ulong)scr->mmio, DP_SRC_BKGD_CLR, 0);
+ OUTREG((ulong)scr->mmio, DP_WRITE_MASK, ~0ul);
+
+ radeonwaitidle(scr);
+
+ scr->fill = radeonfill;
+ scr->scroll = radeonscroll;
+ hwaccel = 1;
+
+ scr->blank = radeonblank;
+ hwblank = 1;
+}
+
+/* hw overlay */
+
+static void
+radeonovlctl(VGAscr *scr, Chan *c, void *data, int len)
+{
+ USED(scr, c, data, len);
+}
+
+static int
+radeonovlwrite(VGAscr *scr, void *data, int len, vlong opt)
+{
+ USED(scr, data, len, opt);
+ return -1;
+}
+
+static void
+radeonflush(VGAscr *scr, Rectangle r)
+{
+ USED(scr, r);
+}
+
+/* Export */
+
+VGAdev vgaradeondev = {
+ "radeon",
+
+ radeonenable,
+ 0, /* disable */
+ 0, /* page */
+ radeonlinear,
+
+ radeondrawinit,
+#ifdef HW_ACCEL
+ radeonfill,
+
+ radeonovlctl,
+ radeonovlwrite,
+ radeonflush,
+#endif
+};
+VGAcur vgaradeoncur = {
+ "radeonhwgc",
+ radeoncurenable,
+ radeoncurdisable,
+ radeoncurload,
+ radeoncurmove,
+ 0 /* doespanning */
+};