Module Name: src Committed By: macallan Date: Tue Oct 9 21:59:19 UTC 2012
Modified Files: src/sys/dev/pci: wcfb.c wcfbreg.h Log Message: add acceleration support, for Sun XVR-1200 and compatible only so far adapted from OpenBSD with various improvements, no support for Expert3D has been added this is still suboptimal since we have to sync the engine all the time but it's an improvement over software-only operation To generate a diff of this commit: cvs rdiff -u -r1.11 -r1.12 src/sys/dev/pci/wcfb.c cvs rdiff -u -r1.1 -r1.2 src/sys/dev/pci/wcfbreg.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/wcfb.c diff -u src/sys/dev/pci/wcfb.c:1.11 src/sys/dev/pci/wcfb.c:1.12 --- src/sys/dev/pci/wcfb.c:1.11 Tue Mar 13 18:40:34 2012 +++ src/sys/dev/pci/wcfb.c Tue Oct 9 21:59:19 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: wcfb.c,v 1.11 2012/03/13 18:40:34 elad Exp $ */ +/* $NetBSD: wcfb.c,v 1.12 2012/10/09 21:59:19 macallan Exp $ */ /*- * Copyright (c) 2010 Michael Lorenz @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: wcfb.c,v 1.11 2012/03/13 18:40:34 elad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: wcfb.c,v 1.12 2012/10/09 21:59:19 macallan Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -104,7 +104,7 @@ struct wcfb_softc { void (*eraserows)(void *, int, int, long); void (*putchar)(void *, int, int, u_int, long); void (*cursor)(void *, int, int, int); - + int sc_is_jfb; }; static void wcfb_init_screen(void *, struct vcons_screen *, int, long *); @@ -130,8 +130,24 @@ static void wcfb_erasecols(void *, int, static void wcfb_copyrows(void *, int, int, int); static void wcfb_eraserows(void *, int, int, long); +static void wcfb_acc_putchar(void *, int, int, u_int, long); +static void wcfb_acc_cursor(void *, int, int, int); +static void wcfb_acc_copycols(void *, int, int, int, int); +static void wcfb_acc_erasecols(void *, int, int, int, long); +static void wcfb_acc_copyrows(void *, int, int, int); +static void wcfb_acc_eraserows(void *, int, int, long); + static void wcfb_putpalreg(struct wcfb_softc *, int, int, int, int); +static void wcfb_bitblt(struct wcfb_softc *, int, int, int, int, int, + int, uint32_t); +static void wcfb_rectfill(struct wcfb_softc *, int, int, int, int, int); +static void wcfb_rop_common(struct wcfb_softc *, bus_addr_t, int, int, int, + int, int, int, uint32_t, int32_t); +static void wcfb_rop_jfb(struct wcfb_softc *, int, int, int, int, int, int, + uint32_t, int32_t); +static int wcfb_rop_wait(struct wcfb_softc *); + static int wcfb_match(device_t parent, cfdata_t match, void *aux) { @@ -156,7 +172,8 @@ wcfb_attach(device_t parent, device_t se uint32_t reg; unsigned long defattr; bool is_console = 0; - void *wtf; + void *wtf; + uint32_t sub; sc->sc_dev = self; sc->putchar = NULL; @@ -195,14 +212,29 @@ wcfb_attach(device_t parent, device_t se sc->sc_fbaddr = bus_space_vaddr(sc->sc_memt, sc->sc_fbh); sc->sc_fb0off = - bus_space_read_4(sc->sc_regt, sc->sc_regh, WC_FB8_ADDR0) - sc->sc_fb; + bus_space_read_4(sc->sc_regt, sc->sc_regh, + WC_FB8_ADDR0) - sc->sc_fb; sc->sc_fb0 = sc->sc_fbaddr + sc->sc_fb0off; sc->sc_fb1off = - bus_space_read_4(sc->sc_regt, sc->sc_regh, WC_FB8_ADDR1) - sc->sc_fb; + bus_space_read_4(sc->sc_regt, sc->sc_regh, + WC_FB8_ADDR1) - sc->sc_fb; sc->sc_fb1 = sc->sc_fbaddr + sc->sc_fb1off; + sub = pci_conf_read(sc->sc_pc, sc->sc_pcitag, PCI_SUBSYS_ID_REG); + printf("subsys: %08x\n", sub); + switch (sub) { + case WC_XVR1200: + sc->sc_is_jfb = 1; + break; + default: + sc->sc_is_jfb = 0; + } + reg = bus_space_read_4(sc->sc_regt, sc->sc_regh, WC_RESOLUTION); sc->sc_height = (reg >> 16) + 1; +#ifdef WCFB_DEBUG + sc->sc_height -= 200; +#endif sc->sc_width = (reg & 0xffff) + 1; sc->sc_stride = 1 << ((bus_space_read_4(sc->sc_regt, sc->sc_regh, WC_CONFIG) & @@ -210,11 +242,14 @@ wcfb_attach(device_t parent, device_t se printf("%s: %d x %d, %d\n", device_xname(sc->sc_dev), sc->sc_width, sc->sc_height, sc->sc_stride); - sc->sc_shadow = kmem_alloc(sc->sc_stride * sc->sc_height, KM_SLEEP); - if (sc->sc_shadow == NULL) { - printf("%s: failed to allocate shadow buffer\n", - device_xname(self)); - return; + if (sc->sc_is_jfb == 0) { + sc->sc_shadow = kmem_alloc(sc->sc_stride * sc->sc_height, + KM_SLEEP); + if (sc->sc_shadow == NULL) { + printf("%s: failed to allocate shadow buffer\n", + device_xname(self)); + return; + } } for (i = 0x40; i < 0x100; i += 16) { @@ -269,10 +304,17 @@ wcfb_attach(device_t parent, device_t se &defattr); sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; - memset(sc->sc_fb0, ri->ri_devcmap[(defattr >> 16) & 0xff], - sc->sc_stride * sc->sc_height); - memset(sc->sc_fb1, ri->ri_devcmap[(defattr >> 16) & 0xff], - sc->sc_stride * sc->sc_height); + if (sc->sc_is_jfb) { + wcfb_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, + ri->ri_devcmap[(defattr >> 16) & 0xff]); + } else { + memset(sc->sc_fb0, + ri->ri_devcmap[(defattr >> 16) & 0xff], + sc->sc_stride * sc->sc_height); + memset(sc->sc_fb1, + ri->ri_devcmap[(defattr >> 16) & 0xff], + sc->sc_stride * sc->sc_height); + } sc->sc_defaultscreen_descr.textops = &ri->ri_ops; sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; sc->sc_defaultscreen_descr.nrows = ri->ri_rows; @@ -340,7 +382,8 @@ wcfb_mmap(void *v, void *vs, off_t offse * restrict all other mappings to processes with superuser privileges * or the kernel itself */ - if (kauth_authorize_machdep(kauth_cred_get(), KAUTH_MACHDEP_UNMANAGEDMEM, + if (kauth_authorize_machdep(kauth_cred_get(), + KAUTH_MACHDEP_UNMANAGEDMEM, NULL, NULL, NULL, NULL) != 0) { aprint_normal_dev(sc->sc_dev, "mmap() rejected.\n"); return -1; @@ -370,8 +413,11 @@ wcfb_init_screen(void *cookie, struct vc ri->ri_stride = sc->sc_stride; ri->ri_flg = RI_CENTER /*| RI_FULLCLEAR*/; - ri->ri_bits = sc->sc_shadow; - + if (sc->sc_is_jfb) { + ri->ri_bits = sc->sc_fb0; + } else { + ri->ri_bits = sc->sc_shadow; + } if (existing) { ri->ri_flg |= RI_CLEAR; } @@ -389,12 +435,21 @@ wcfb_init_screen(void *cookie, struct vc sc->copycols = ri->ri_ops.copycols; sc->erasecols = ri->ri_ops.erasecols; - ri->ri_ops.copyrows = wcfb_copyrows; - ri->ri_ops.copycols = wcfb_copycols; - ri->ri_ops.eraserows = wcfb_eraserows; - ri->ri_ops.erasecols = wcfb_erasecols; - ri->ri_ops.putchar = wcfb_putchar; - ri->ri_ops.cursor = wcfb_cursor; + if (sc->sc_is_jfb) { + ri->ri_ops.copyrows = wcfb_acc_copyrows; + ri->ri_ops.copycols = wcfb_acc_copycols; + ri->ri_ops.eraserows = wcfb_acc_eraserows; + ri->ri_ops.erasecols = wcfb_acc_erasecols; + ri->ri_ops.putchar = wcfb_acc_putchar; + ri->ri_ops.cursor = wcfb_acc_cursor; + } else { + ri->ri_ops.copyrows = wcfb_copyrows; + ri->ri_ops.copycols = wcfb_copycols; + ri->ri_ops.eraserows = wcfb_eraserows; + ri->ri_ops.erasecols = wcfb_erasecols; + ri->ri_ops.putchar = wcfb_putchar; + ri->ri_ops.cursor = wcfb_cursor; + } } static void @@ -572,3 +627,264 @@ wcfb_eraserows(void *cookie, int row, in to1 += sc->sc_stride; } } + +static void +wcfb_bitblt(struct wcfb_softc *sc, int sx, int sy, int dx, int dy, int w, + int h, uint32_t rop) +{ + wcfb_rop_wait(sc); + wcfb_rop_jfb(sc, sx, sy, dx, dy, w, h, rop, 0xff); +} + +static void +wcfb_rectfill(struct wcfb_softc *sc, int x, int y, int w, int h, int bg) +{ + int32_t mask; + + /* pixels to set... */ + mask = 0xff & bg; + if (mask != 0) { + wcfb_rop_wait(sc); + wcfb_rop_jfb(sc, x, y, x, y, w, h, WC_ROP_SET, mask); + } + + /* pixels to clear... */ + mask = 0xff & ~bg; + if (mask != 0) { + wcfb_rop_wait(sc); + wcfb_rop_jfb(sc, x, y, x, y, w, h, WC_ROP_CLEAR, mask); + } +} + +void +wcfb_rop_common(struct wcfb_softc *sc, bus_addr_t reg, int sx, int sy, + int dx, int dy, int w, int h, uint32_t rop, int32_t planemask) +{ + int dir = 0; + + /* + * Compute rop direction. This only really matters for + * screen-to-screen copies. + */ + if (sy < dy /* && sy + h > dy */) { + sy += h - 1; + dy += h; + dir |= WC_BLT_DIR_BACKWARDS_Y; + } + if (sx < dx /* && sx + w > dx */) { + sx += w - 1; + dx += w; + dir |= WC_BLT_DIR_BACKWARDS_X; + } + + /* Which one of those below is your magic number for today? */ + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x61000001); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x6301c080); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x80000000); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, rop); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, planemask); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x64000303); + /* + * This value is a pixel offset within the destination area. It is + * probably used to define complex polygon shapes, with the + * last pixel in the list being back to (0,0). + */ + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, WCFB_COORDS(0, 0)); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x00030000); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x2200010d); + + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x33f01000 | dir); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, WCFB_COORDS(dx, dy)); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, WCFB_COORDS(w, h)); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, WCFB_COORDS(sx, sy)); +} + + +static void +wcfb_rop_jfb(struct wcfb_softc *sc, int sx, int sy, int dx, int dy, + int w, int h, uint32_t rop, int32_t planemask) +{ + bus_addr_t reg = WC_JFB_ENGINE; + uint32_t spr, splr; + +#if 0 + /* + * Pick the current spr and splr values from the communication + * area if possible. + */ + if (sc->sc_comm != NULL) { + spr = sc->sc_comm[IFB_SHARED_TERM8_SPR >> 2]; + splr = sc->sc_comm[IFB_SHARED_TERM8_SPLR >> 2]; + } else +#endif + { + /* supposedly sane defaults */ + spr = 0x54ff0303; + splr = 0x5c0000ff; + } + + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x00400016); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x5b000002); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x5a000000); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, spr); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, splr); + + wcfb_rop_common(sc, reg, sx, sy, dx, dy, w, h, rop, planemask); + + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x5a000001); + bus_space_write_4(sc->sc_regt, sc->sc_regh, reg, 0x5b000001); +} + +static int +wcfb_rop_wait(struct wcfb_softc *sc) +{ + int i; + + for (i = 1000000; i != 0; i--) { + if (bus_space_read_4(sc->sc_regt, sc->sc_regh, + WC_STATUS) & WC_STATUS_DONE) + break; + delay(1); + } + + return i; +} + +static void +wcfb_acc_putchar(void *cookie, int row, int col, u_int c, long attr) +{ + struct rasops_info *ri = cookie; + struct vcons_screen *scr = ri->ri_hw; + struct wcfb_softc *sc = scr->scr_cookie; + struct wsdisplay_font *font = PICK_FONT(ri, c); + int x, y, wi, he; + uint32_t bg; + + wi = font->fontwidth; + he = font->fontheight; + x = ri->ri_xorigin + col * wi; + y = ri->ri_yorigin + row * he; + bg = ri->ri_devcmap[(attr >> 16) & 0xf]; + if (c == 0x20) { + wcfb_rectfill(sc, x, y, wi, he, bg); + return; + } + /* we wait until the blitter is idle... */ + wcfb_rop_wait(sc); + /* ... draw the character into buffer 0 ... */ + sc->putchar(ri, row, col, c, attr); + /* ... and then blit it into buffer 1 */ + wcfb_bitblt(sc, x, y, x, y, wi, he, WC_ROP_COPY); +} + +static void +wcfb_acc_cursor(void *cookie, int on, int row, int col) +{ + struct rasops_info *ri = cookie; + struct vcons_screen *scr = ri->ri_hw; + struct wcfb_softc *sc = scr->scr_cookie; + int x, y, wi, he; + + wi = ri->ri_font->fontwidth; + he = ri->ri_font->fontheight; + + if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { + x = ri->ri_ccol * wi + ri->ri_xorigin; + y = ri->ri_crow * he + ri->ri_yorigin; + if (ri->ri_flg & RI_CURSOR) { + wcfb_bitblt(sc, x, y, x, y, wi, he, WC_ROP_XOR); + ri->ri_flg &= ~RI_CURSOR; + } + ri->ri_crow = row; + ri->ri_ccol = col; + if (on) { + x = ri->ri_ccol * wi + ri->ri_xorigin; + y = ri->ri_crow * he + ri->ri_yorigin; + wcfb_bitblt(sc, x, y, x, y, wi, he, WC_ROP_XOR); + ri->ri_flg |= RI_CURSOR; + } + } else { + scr->scr_ri.ri_crow = row; + scr->scr_ri.ri_ccol = col; + scr->scr_ri.ri_flg &= ~RI_CURSOR; + } + +} + +static void +wcfb_acc_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) +{ + struct rasops_info *ri = cookie; + struct vcons_screen *scr = ri->ri_hw; + struct wcfb_softc *sc = scr->scr_cookie; + int32_t xs, xd, y, width, height; + + if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { + xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; + xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; + y = ri->ri_yorigin + ri->ri_font->fontheight * row; + width = ri->ri_font->fontwidth * ncols; + height = ri->ri_font->fontheight; + wcfb_bitblt(sc, xs, y, xd, y, width, height, WC_ROP_COPY); + } +} + +static void +wcfb_acc_erasecols(void *cookie, int row, int startcol, int ncols, + long fillattr) +{ + struct rasops_info *ri = cookie; + struct vcons_screen *scr = ri->ri_hw; + struct wcfb_softc *sc = scr->scr_cookie; + int32_t x, y, width, height, fg, bg, ul; + + if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { + x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; + y = ri->ri_yorigin + ri->ri_font->fontheight * row; + width = ri->ri_font->fontwidth * ncols; + height = ri->ri_font->fontheight; + rasops_unpack_attr(fillattr, &fg, &bg, &ul); + + wcfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); + } +} + +static void +wcfb_acc_copyrows(void *cookie, int srcrow, int dstrow, int nrows) +{ + struct rasops_info *ri = cookie; + struct vcons_screen *scr = ri->ri_hw; + struct wcfb_softc *sc = scr->scr_cookie; + int32_t x, ys, yd, width, height; + + if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { + x = ri->ri_xorigin; + ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; + yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; + width = ri->ri_emuwidth; + height = ri->ri_font->fontheight * nrows; + wcfb_bitblt(sc, x, ys, x, yd, width, height, WC_ROP_COPY); + } +} + +static void +wcfb_acc_eraserows(void *cookie, int row, int nrows, long fillattr) +{ + struct rasops_info *ri = cookie; + struct vcons_screen *scr = ri->ri_hw; + struct wcfb_softc *sc = scr->scr_cookie; + int32_t x, y, width, height, fg, bg, ul; + + if ((sc->sc_locked == 0) && (sc->sc_mode == WSDISPLAYIO_MODE_EMUL)) { + x = ri->ri_xorigin; + y = ri->ri_yorigin + ri->ri_font->fontheight * row; + width = ri->ri_emuwidth; + height = ri->ri_font->fontheight * nrows; + rasops_unpack_attr(fillattr, &fg, &bg, &ul); + + wcfb_rectfill(sc, x, y, width, height, ri->ri_devcmap[bg]); + } +} Index: src/sys/dev/pci/wcfbreg.h diff -u src/sys/dev/pci/wcfbreg.h:1.1 src/sys/dev/pci/wcfbreg.h:1.2 --- src/sys/dev/pci/wcfbreg.h:1.1 Wed Mar 10 05:16:17 2010 +++ src/sys/dev/pci/wcfbreg.h Tue Oct 9 21:59:19 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: wcfbreg.h,v 1.1 2010/03/10 05:16:17 macallan Exp $ */ +/* $NetBSD: wcfbreg.h,v 1.2 2012/10/09 21:59:19 macallan Exp $ */ /*- * Copyright (c) 2010 Michael Lorenz @@ -34,14 +34,36 @@ #ifndef WCFBREG_H #define WCFBREG_H -#define WC_RESOLUTION 0x8070 -#define WC_CONFIG 0x8074 /* contains log2(stride) in 0x00ff0000 */ -#define WC_FB8_ADDR0 0x8080 -#define WC_FB8_ADDR1 0x8084 +#define WC_IFB_ENGINE 0x8000 +#define WC_JFB_ENGINE 0x6000 + +#define WC_COMPONENT_SELECT 0x8040 +#define WC_STATUS 0x8044 + #define WC_STATUS_DONE 0x00000004 +#define WC_RESOLUTION 0x8070 +#define WC_CONFIG 0x8074 /* log2(stride) in 0x00ff0000 */ +#define WC_FB32_ADDR0 0x8078 +#define WC_FB32_ADDR1 0x807c +#define WC_FB8_ADDR0 0x8080 +#define WC_FB8_ADDR1 0x8084 +#define WC_FB32_UNKNOWN 0x8088 +#define WC_FB8_UNKNOWN1 0x808c +#define WC_FB8_UNKNOWN2 0x8090 + +/* standard ternary ROP in <<16 */ +#define WC_ROP_CLEAR 0x00000000 +#define WC_ROP_COPY 0x00330000 +#define WC_ROP_XOR 0x00cc0000 +#define WC_ROP_SET 0x00ff0000 #define WC_CMAP_INDEX 0x80bc #define WC_CMAP_DATA 0x80c0 +#define WCFB_COORDS(x, y) ((y) << 16 | (x)) +/* blitter directions */ +#define WC_BLT_DIR_BACKWARDS_Y (0x08 | 0x02) +#define WC_BLT_DIR_BACKWARDS_X (0x04 | 0x01) + /* * 80e4 DPMS state register * States ``off'' and ``suspend'' need chip reprogramming before video can @@ -54,3 +76,6 @@ #define WC_DPMS_ON 0x00000003 #endif + +#define WC_XVR1200 0x10443d3d +