Module Name: src Committed By: macallan Date: Thu Dec 29 20:14:40 UTC 2011
Modified Files: src/sys/dev/pci: radeonfb.c Log Message: rework putchar(): - get rid of engine stalls when using the blitter to draw characters - add a wrapper for non-accelerated putchar() so we only wait for the engine when we actually want to scribble into video memory - rework accelerated putchar(), should work on R3xx now but needs testing To generate a diff of this commit: cvs rdiff -u -r1.47 -r1.48 src/sys/dev/pci/radeonfb.c 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/radeonfb.c diff -u src/sys/dev/pci/radeonfb.c:1.47 src/sys/dev/pci/radeonfb.c:1.48 --- src/sys/dev/pci/radeonfb.c:1.47 Thu Dec 29 20:09:14 2011 +++ src/sys/dev/pci/radeonfb.c Thu Dec 29 20:14:39 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: radeonfb.c,v 1.47 2011/12/29 20:09:14 macallan Exp $ */ +/* $NetBSD: radeonfb.c,v 1.48 2011/12/29 20:14:39 macallan Exp $ */ /*- * Copyright (c) 2006 Itronix Inc. @@ -70,7 +70,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: radeonfb.c,v 1.47 2011/12/29 20:09:14 macallan Exp $"); +__KERNEL_RCSID(0, "$NetBSD: radeonfb.c,v 1.48 2011/12/29 20:14:39 macallan Exp $"); #define RADEONFB_DEFAULT_DEPTH 8 @@ -99,6 +99,7 @@ __KERNEL_RCSID(0, "$NetBSD: radeonfb.c,v #include <dev/pci/radeonfbreg.h> #include <dev/pci/radeonfbvar.h> #include "opt_radeonfb.h" +#include "opt_vcons.h" static int radeonfb_match(device_t, cfdata_t, void *); static void radeonfb_attach(device_t, device_t, void *); @@ -140,9 +141,6 @@ static void radeonfb_rectfill(struct ra int width, int height, uint32_t color); static void radeonfb_bitblt(struct radeonfb_display *, int srcx, int srcy, int dstx, int dsty, int width, int height, int rop, uint32_t mask); -static void radeonfb_feed_bytes(struct radeonfb_display *, int, uint8_t *); -static void radeonfb_setup_mono(struct radeonfb_display *, int, int, int, - int, uint32_t, uint32_t); /* hw cursor support */ static void radeonfb_cursor_cmap(struct radeonfb_display *); @@ -1080,6 +1078,11 @@ radeonfb_ioctl(void *v, void *vs, return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc, sc->sc_pt, d); + case WSDISPLAYIO_GET_EDID: { + struct wsdisplayio_edid_info *ei = d; + return wsdisplayio_get_edid(sc->sc_dev, ei); + } + default: return EPASSTHROUGH; } @@ -2161,6 +2164,10 @@ radeonfb_init_screen(void *cookie, struc ri->ri_flg = RI_CENTER; ri->ri_bits = (void *)dp->rd_fbptr; +#ifdef VCONS_DRAW_INTR + scr->scr_flags |= VCONS_DONT_READ; +#endif + /* XXX: 32 bpp only */ /* this is rgb in "big-endian order..." */ ri->ri_rnum = 8; @@ -2196,10 +2203,15 @@ radeonfb_init_screen(void *cookie, struc ri->ri_ops.eraserows = radeonfb_eraserows; ri->ri_ops.erasecols = radeonfb_erasecols; ri->ri_ops.allocattr = radeonfb_allocattr; - if (!IS_R300(dp->rd_softc)) { - ri->ri_ops.putchar = radeonfb_putchar; - } else { + if (IS_R300(dp->rd_softc)) { + /* + * radeonfb_putchar() doesn't work right on some R3xx + * so we use software drawing here, the wrapper just makes + * sure the engine is idle before scribbling into vram + */ ri->ri_ops.putchar = radeonfb_putchar_wrapper; + } else { + ri->ri_ops.putchar = radeonfb_putchar; } ri->ri_ops.cursor = radeonfb_cursor; } @@ -2380,10 +2392,15 @@ radeonfb_putchar(void *cookie, int row, struct rasops_info *ri = cookie; struct vcons_screen *scr = ri->ri_hw; struct radeonfb_display *dp = scr->scr_cookie; + struct radeonfb_softc *sc = dp->rd_softc; struct wsdisplay_font *font = PICK_FONT(ri, c); - uint32_t x, y, w, h; - uint32_t bg, fg, flg; - uint8_t *data; + uint32_t w, h; + int xd, yd, offset, i; + uint32_t bg, fg, gmc; + uint32_t reg; + uint8_t *data8; + uint16_t *data16; + void *data; if (dp->rd_wsmode != WSDISPLAYIO_MODE_EMUL) return; @@ -2394,26 +2411,67 @@ radeonfb_putchar(void *cookie, int row, w = font->fontwidth; h = font->fontheight; - flg = attr & 0xff; - if (flg & WSATTR_REVERSE) { - fg = ri->ri_devcmap[(attr >> 16) & 0xf]; - bg = ri->ri_devcmap[(attr >> 24) & 0xf]; - } else { - bg = ri->ri_devcmap[(attr >> 16) & 0xf]; - fg = ri->ri_devcmap[(attr >> 24) & 0xf]; - } + bg = ri->ri_devcmap[(attr >> 16) & 0xf]; + fg = ri->ri_devcmap[(attr >> 24) & 0xf]; - x = ri->ri_xorigin + col * w; - y = ri->ri_yorigin + row * h; + xd = ri->ri_xorigin + col * w; + yd = ri->ri_yorigin + row * h; if (c == 0x20) { - radeonfb_rectfill(dp, x, y, w, h, bg); - } else { - data = (uint8_t *)font->data + - (c - font->firstchar) * ri->ri_fontscale; + radeonfb_rectfill(dp, xd, yd, w, h, bg); + return; + } + data = (uint8_t *)font->data + (c - font->firstchar) * ri->ri_fontscale; - radeonfb_setup_mono(dp, x, y, w, h, fg, bg); - radeonfb_feed_bytes(dp, ri->ri_fontscale, data); + gmc = dp->rd_format << RADEON_GMC_DST_DATATYPE_SHIFT; + + radeonfb_wait_fifo(sc, 9); + + PUT32(sc, RADEON_DP_GUI_MASTER_CNTL, + RADEON_GMC_BRUSH_NONE | + RADEON_GMC_SRC_DATATYPE_MONO_FG_BG | + RADEON_GMC_DST_CLIPPING | + RADEON_ROP3_S | + RADEON_DP_SRC_SOURCE_HOST_DATA | + RADEON_GMC_CLR_CMP_CNTL_DIS | + RADEON_GMC_WR_MSK_DIS | + gmc); + + PUT32(sc, RADEON_SC_LEFT, xd); + PUT32(sc, RADEON_SC_RIGHT, xd + w); + PUT32(sc, RADEON_DP_SRC_FRGD_CLR, fg); + PUT32(sc, RADEON_DP_SRC_BKGD_CLR, bg); + PUT32(sc, RADEON_DP_CNTL, + RADEON_DST_X_LEFT_TO_RIGHT | + RADEON_DST_Y_TOP_TO_BOTTOM); + + PUT32(sc, RADEON_SRC_X_Y, 0); + offset = 32 - (font->stride << 3); + PUT32(sc, RADEON_DST_X_Y, ((xd - offset) << 16) | yd); + PUT32(sc, RADEON_DST_WIDTH_HEIGHT, (32 << 16) | h); + + radeonfb_wait_fifo(sc, h); + switch (font->stride) { + case 1: { + data8 = data; + for (i = 0; i < h; i++) { + reg = *data8; + bus_space_write_stream_4(sc->sc_regt, + sc->sc_regh, RADEON_HOST_DATA0, reg); + data8++; + } + break; + } + case 2: { + data16 = data; + for (i = 0; i < h; i++) { + reg = *data16; + bus_space_write_stream_4(sc->sc_regt, + sc->sc_regh, RADEON_HOST_DATA0, reg); + data16++; + } + break; + } } } @@ -2562,72 +2620,6 @@ radeonfb_allocattr(void *cookie, int fg, /* * Underlying acceleration support. */ -static void -radeonfb_setup_mono(struct radeonfb_display *dp, int xd, int yd, int width, - int height, uint32_t fg, uint32_t bg) -{ - struct radeonfb_softc *sc = dp->rd_softc; - uint32_t gmc; - uint32_t padded_width = (width+7) & 0xfff8; - uint32_t topleft, bottomright; - - gmc = dp->rd_format << RADEON_GMC_DST_DATATYPE_SHIFT; - - if (width != padded_width) { - - radeonfb_wait_fifo(sc, 2); - topleft = ((yd << 16) & 0x1fff0000) | (xd & 0x1fff); - bottomright = (((yd + height) << 16) & 0x1fff0000) | - ((xd + width) & 0x1fff); - PUT32(sc, RADEON_SC_TOP_LEFT, topleft); - PUT32(sc, RADEON_SC_BOTTOM_RIGHT, bottomright); - } - - radeonfb_wait_fifo(sc, 5); - - PUT32(sc, RADEON_DP_GUI_MASTER_CNTL, - RADEON_GMC_BRUSH_NONE | - RADEON_GMC_SRC_DATATYPE_MONO_FG_BG | - //RADEON_GMC_BYTE_LSB_TO_MSB | - RADEON_GMC_DST_CLIPPING | - RADEON_ROP3_S | - RADEON_DP_SRC_SOURCE_HOST_DATA | - RADEON_GMC_CLR_CMP_CNTL_DIS | - RADEON_GMC_WR_MSK_DIS | - gmc); - - PUT32(sc, RADEON_DP_SRC_FRGD_CLR, fg); - PUT32(sc, RADEON_DP_SRC_BKGD_CLR, bg); - - PUT32(sc, RADEON_DST_X_Y, (xd << 16) | yd); - PUT32(sc, RADEON_DST_WIDTH_HEIGHT, (padded_width << 16) | height); - -} - -static void -radeonfb_feed_bytes(struct radeonfb_display *dp, int count, uint8_t *data) -{ - struct radeonfb_softc *sc = dp->rd_softc; - int i; - uint32_t latch = 0; - int shift = 0; - - for (i = 0; i < count; i++) { - latch |= (data[i] << shift); - if (shift == 24) { - radeonfb_wait_fifo(sc, 1); - PUT32(sc, RADEON_HOST_DATA0, latch); - latch = 0; - shift = 0; - } else - shift += 8; - } - if (shift != 0) { - radeonfb_wait_fifo(sc, 1); - PUT32(sc, RADEON_HOST_DATA0, latch); - } - radeonfb_unclip(sc); -} static void radeonfb_rectfill(struct radeonfb_display *dp, int dstx, int dsty, @@ -2654,12 +2646,6 @@ radeonfb_rectfill(struct radeonfb_displa PUT32(sc, RADEON_DST_Y_X, (dsty << 16) | dstx); PUT32(sc, RADEON_DST_WIDTH_HEIGHT, (width << 16) | (height)); - /* - * XXX: we don't wait for the fifo to empty -- that would slow - * things down! The linux radeonfb driver waits, but xfree doesn't - */ - /* XXX: for now we do, to make it safe for direct drawing */ - radeonfb_engine_idle(sc); } static void @@ -2701,28 +2687,16 @@ radeonfb_bitblt(struct radeonfb_display PUT32(sc, RADEON_SRC_Y_X, (srcy << 16) | srcx); PUT32(sc, RADEON_DST_Y_X, (dsty << 16) | dstx); PUT32(sc, RADEON_DST_WIDTH_HEIGHT, (width << 16) | (height)); - - /* - * XXX: we don't wait for the fifo to empty -- that would slow - * things down! The linux radeonfb driver waits, but xfree doesn't - */ - /* XXX: for now we do, to make it safe for direct drawing */ - radeonfb_engine_idle(sc); } static void radeonfb_engine_idle(struct radeonfb_softc *sc) { - int i; radeonfb_wait_fifo(sc, 64); - for (i = RADEON_TIMEOUT; i; i--) { - if ((GET32(sc, RADEON_RBBM_STATUS) & - RADEON_RBBM_ACTIVE) == 0) { - radeonfb_engine_flush(sc); - break; - } - } + while ((GET32(sc, RADEON_RBBM_STATUS) & + RADEON_RBBM_ACTIVE) != 0); + radeonfb_engine_flush(sc); } static void @@ -2745,15 +2719,23 @@ radeonfb_wait_fifo(struct radeonfb_softc static void radeonfb_engine_flush(struct radeonfb_softc *sc) { - int i; - SET32(sc, RADEON_RB2D_DSTCACHE_CTLSTAT, RADEON_RB2D_DC_FLUSH_ALL); - for (i = RADEON_TIMEOUT; i; i--) { - if ((GET32(sc, RADEON_RB2D_DSTCACHE_CTLSTAT) & - RADEON_RB2D_DC_BUSY) == 0) - break; + int i = 0; + + if (IS_R300(sc)) { + SET32(sc, R300_DSTCACHE_CTLSTAT, R300_RB2D_DC_FLUSH_ALL); + while (GET32(sc, R300_DSTCACHE_CTLSTAT) & R300_RB2D_DC_BUSY) { + i++; + } + } else { + SET32(sc, RADEON_RB2D_DSTCACHE_CTLSTAT, + RADEON_RB2D_DC_FLUSH_ALL); + while (GET32(sc, RADEON_RB2D_DSTCACHE_CTLSTAT) & + RADEON_RB2D_DC_BUSY) { + i++; + } } #ifdef DIAGNOSTIC - if (!i) + if (i > RADEON_TIMEOUT) printf("%s: engine flush timed out!\n", XNAME(sc)); #endif } @@ -2815,7 +2797,7 @@ radeonfb_engine_init(struct radeonfb_dis RADEON_GMC_BRUSH_SOLID_COLOR | RADEON_GMC_SRC_DATATYPE_COLOR); - radeonfb_wait_fifo(sc, 7); + radeonfb_wait_fifo(sc, 10); PUT32(sc, RADEON_DST_LINE_START, 0); PUT32(sc, RADEON_DST_LINE_END, 0); PUT32(sc, RADEON_DP_BRUSH_FRGD_CLR, 0xffffffff); @@ -2823,7 +2805,9 @@ radeonfb_engine_init(struct radeonfb_dis PUT32(sc, RADEON_DP_SRC_FRGD_CLR, 0xffffffff); PUT32(sc, RADEON_DP_SRC_BKGD_CLR, 0); PUT32(sc, RADEON_DP_WRITE_MASK, 0xffffffff); - + PUT32(sc, RADEON_SC_TOP_LEFT, 0); + PUT32(sc, RADEON_SC_BOTTOM_RIGHT, 0x1fff1fff); + PUT32(sc, RADEON_AUX_SC_CNTL, 0); radeonfb_engine_idle(sc); }