diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /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-x | sys/src/9/pc/vgaradeon.c | 520 |
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 */ +}; |