summaryrefslogtreecommitdiff
path: root/sys/arch/sgi/dev/gbe.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/sgi/dev/gbe.c')
-rw-r--r--sys/arch/sgi/dev/gbe.c555
1 files changed, 498 insertions, 57 deletions
diff --git a/sys/arch/sgi/dev/gbe.c b/sys/arch/sgi/dev/gbe.c
index eca78c98b55..734a36d027c 100644
--- a/sys/arch/sgi/dev/gbe.c
+++ b/sys/arch/sgi/dev/gbe.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: gbe.c,v 1.6 2008/04/07 22:34:21 miod Exp $ */
+/* $OpenBSD: gbe.c,v 1.7 2009/02/24 14:37:29 jsing Exp $ */
/*
- * Copyright (c) 2007, Joel Sing <jsing@openbsd.org>
+ * Copyright (c) 2007, 2008, 2009 Joel Sing <jsing@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,7 +17,7 @@
*/
/*
- * Graphics Back End (GBE) Framebuffer for SGI O2
+ * Graphics Back End (GBE) Framebuffer for SGI O2.
*/
#include <sys/param.h>
@@ -60,7 +60,8 @@ struct gbe_cmap {
struct gbe_screen {
struct device *sc; /* Back pointer. */
- struct rasops_info ri; /* Raster display info. */
+ struct rasops_info ri; /* Screen raster display info. */
+ struct rasops_info ri_tile; /* Raster info for rasops tile. */
struct gbe_cmap cmap; /* Display colour map. */
int fb_size; /* Size of framebuffer memory. */
@@ -70,11 +71,16 @@ struct gbe_screen {
paddr_t tm_phys; /* Physical address of tilemap. */
caddr_t fb; /* Address of framebuffer memory. */
paddr_t fb_phys; /* Physical address of framebuffer. */
+ caddr_t ro; /* Address of rasops tile. */
+ paddr_t ro_phys; /* Physical address of rasops tile. */
int width; /* Width in pixels. */
int height; /* Height in pixels. */
int depth; /* Colour depth in bits. */
+ int mode; /* Display mode. */
+ int bufmode; /* Rendering engine buffer mode. */
int linebytes; /* Bytes per line. */
+ int ro_curpos; /* Current position in rasops tile. */
};
/*
@@ -84,7 +90,8 @@ struct gbe_softc {
struct device sc_dev;
bus_space_tag_t iot;
- bus_space_handle_t ioh;
+ bus_space_handle_t ioh; /* GBE registers. */
+ bus_space_handle_t re_ioh; /* Rendering engine registers. */
bus_dma_tag_t dmat;
int rev; /* Hardware revision. */
@@ -102,6 +109,7 @@ void gbe_enable(struct gbe_softc *);
void gbe_disable(struct gbe_softc *);
void gbe_setup(struct gbe_softc *);
void gbe_setcolour(struct gbe_softc *, u_int, u_int8_t, u_int8_t, u_int8_t);
+void gbe_wait_re_idle(struct gbe_softc *);
/*
* Colour map handling for indexed modes.
@@ -122,6 +130,19 @@ int gbe_show_screen(void *, void *, int, void (*)(void *, int, int),
void *);
void gbe_burner(void *, u_int, u_int);
+/*
+ * Hardware acceleration for rasops.
+ */
+void gbe_rop(struct gbe_softc *, int, int, int, int, int);
+void gbe_copyrect(struct gbe_softc *, int, int, int, int, int, int, int);
+void gbe_fillrect(struct gbe_softc *, int, int, int, int, int);
+void gbe_do_cursor(struct rasops_info *);
+void gbe_putchar(void *, int, int, u_int, long);
+void gbe_copycols(void *, int, int, int, int);
+void gbe_erasecols(void *, int, int, int, long);
+void gbe_copyrows(void *, int, int, int);
+void gbe_eraserows(void *, int, int, long);
+
static struct gbe_screen gbe_consdata;
static int gbe_console;
@@ -180,10 +201,13 @@ gbe_attach(struct device *parent, struct device *self, void *aux)
struct wsemuldisplaydev_attach_args waa;
bus_dma_segment_t tm_segs[1];
bus_dma_segment_t fb_segs[1];
+ bus_dma_segment_t ro_segs[1];
bus_dmamap_t tm_dmamap;
bus_dmamap_t fb_dmamap;
+ bus_dmamap_t ro_dmamap;
int tm_nsegs;
int fb_nsegs;
+ int ro_nsegs;
uint32_t val;
long attr;
@@ -202,6 +226,8 @@ gbe_attach(struct device *parent, struct device *self, void *aux)
*/
gsc->ioh = PHYS_TO_UNCACHED(GBE_BASE);
+ gsc->re_ioh = PHYS_TO_UNCACHED(RE_BASE);
+
gsc->rev = bus_space_read_4(gsc->iot, gsc->ioh, GBE_CTRL_STAT)
& 0xf;
@@ -235,14 +261,20 @@ gbe_attach(struct device *parent, struct device *self, void *aux)
screen = gsc->curscr;
/*
- * Setup bus space mapping.
+ * Setup bus space mappings.
*/
if (bus_space_map(gsc->iot, GBE_BASE - CRIMEBUS_BASE, GBE_REG_SIZE,
BUS_SPACE_MAP_LINEAR, &gsc->ioh)) {
- printf("failed to map bus space!\n");
+ printf("failed to map framebuffer bus space!\n");
return;
}
+ if (bus_space_map(gsc->iot, RE_BASE - CRIMEBUS_BASE, RE_REG_SIZE,
+ BUS_SPACE_MAP_LINEAR, &gsc->re_ioh)) {
+ printf("failed to map rendering engine bus space!\n");
+ goto fail0;
+ }
+
/* Determine GBE revision. */
gsc->rev = bus_space_read_4(gsc->iot, gsc->ioh, GBE_CTRL_STAT) & 0xf;
@@ -254,7 +286,7 @@ gbe_attach(struct device *parent, struct device *self, void *aux)
if (screen->width == 0 || screen->height == 0) {
printf("device has not been setup by firmware!\n");
- goto fail0;
+ goto fail1;
}
/* Setup screen defaults. */
@@ -264,30 +296,30 @@ gbe_attach(struct device *parent, struct device *self, void *aux)
screen->linebytes = screen->width * screen->depth / 8;
/*
- * Setup DMA for tile map.
+ * Setup DMA for tilemap.
*/
if (bus_dmamap_create(gsc->dmat, screen->tm_size, 1, screen->tm_size,
0, BUS_DMA_NOWAIT, &tm_dmamap)) {
- printf("failed to create DMA map for tile map!\n");
- goto fail0;
+ printf("failed to create DMA map for tilemap!\n");
+ goto fail1;
}
if (bus_dmamem_alloc(gsc->dmat, screen->tm_size, 65536, 0, tm_segs, 1,
&tm_nsegs, BUS_DMA_NOWAIT)) {
- printf("failed to allocate DMA memory for tile map!\n");
- goto fail1;
+ printf("failed to allocate DMA memory for tilemap!\n");
+ goto fail2;
}
if (bus_dmamem_map(gsc->dmat, tm_segs, tm_nsegs, screen->tm_size,
&screen->tm, BUS_DMA_COHERENT)) {
- printf("failed to map DMA memory for tile map!\n");
- goto fail2;
+ printf("failed to map DMA memory for tilemap!\n");
+ goto fail3;
}
if (bus_dmamap_load(gsc->dmat, tm_dmamap, screen->tm, screen->tm_size,
NULL, BUS_DMA_NOWAIT)){
printf("failed to load DMA map for tilemap\n");
- goto fail3;
+ goto fail4;
}
/*
@@ -296,29 +328,57 @@ gbe_attach(struct device *parent, struct device *self, void *aux)
if (bus_dmamap_create(gsc->dmat, screen->fb_size, 1, screen->fb_size,
0, BUS_DMA_NOWAIT, &fb_dmamap)) {
printf("failed to create DMA map for framebuffer!\n");
- goto fail4;
+ goto fail5;
}
if (bus_dmamem_alloc(gsc->dmat, screen->fb_size, 65536, 0, fb_segs,
1, &fb_nsegs, BUS_DMA_NOWAIT)) {
printf("failed to allocate DMA memory for framebuffer!\n");
- goto fail5;
+ goto fail6;
}
if (bus_dmamem_map(gsc->dmat, fb_segs, fb_nsegs, screen->fb_size,
&screen->fb, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) {
printf("failed to map DMA memory for framebuffer!\n");
- goto fail6;
+ goto fail7;
}
if (bus_dmamap_load(gsc->dmat, fb_dmamap, screen->fb, screen->fb_size,
NULL, BUS_DMA_NOWAIT)) {
printf("failed to load DMA map for framebuffer\n");
- goto fail7;
+ goto fail8;
+ }
+
+ /*
+ * Setup DMA for rasops tile.
+ */
+ if (bus_dmamap_create(gsc->dmat, GBE_TILE_SIZE, 1, GBE_TILE_SIZE,
+ 0, BUS_DMA_NOWAIT, &ro_dmamap)) {
+ printf("failed to create DMA map for rasops tile!\n");
+ goto fail9;
+ }
+
+ if (bus_dmamem_alloc(gsc->dmat, GBE_TILE_SIZE, 65536, 0, ro_segs,
+ 1, &ro_nsegs, BUS_DMA_NOWAIT)) {
+ printf("failed to allocate DMA memory for rasops tile!\n");
+ goto fail10;
+ }
+
+ if (bus_dmamem_map(gsc->dmat, ro_segs, ro_nsegs, GBE_TILE_SIZE,
+ &screen->ro, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) {
+ printf("failed to map DMA memory for rasops tile!\n");
+ goto fail11;
+ }
+
+ if (bus_dmamap_load(gsc->dmat, ro_dmamap, screen->ro, GBE_TILE_SIZE,
+ NULL, BUS_DMA_NOWAIT)) {
+ printf("failed to load DMA map for rasops tile\n");
+ goto fail12;
}
screen->tm_phys = tm_dmamap->dm_segs[0].ds_addr;
screen->fb_phys = fb_dmamap->dm_segs[0].ds_addr;
+ screen->ro_phys = ro_dmamap->dm_segs[0].ds_addr;
shutdownhook_establish((void(*)(void *))gbe_disable, self);
@@ -331,6 +391,9 @@ gbe_attach(struct device *parent, struct device *self, void *aux)
if (screen->depth == 8)
gbe_loadcmap(screen, 0, 255);
+ /* Clear framebuffer. */
+ gbe_fillrect(gsc, 0, 0, screen->width, screen->height, 0);
+
printf("rev %u, %iMB, %dx%d at %d bits\n", gsc->rev,
screen->fb_size >> 20, screen->width, screen->height,
screen->depth);
@@ -354,20 +417,30 @@ gbe_attach(struct device *parent, struct device *self, void *aux)
return;
-fail7:
+fail12:
+ bus_dmamem_unmap(gsc->dmat, screen->ro, GBE_TILE_SIZE);
+fail11:
+ bus_dmamem_free(gsc->dmat, ro_segs, ro_nsegs);
+fail10:
+ bus_dmamap_destroy(gsc->dmat, ro_dmamap);
+fail9:
+ bus_dmamap_unload(gsc->dmat, fb_dmamap);
+fail8:
bus_dmamem_unmap(gsc->dmat, screen->fb, screen->fb_size);
-fail6:
+fail7:
bus_dmamem_free(gsc->dmat, fb_segs, fb_nsegs);
-fail5:
+fail6:
bus_dmamap_destroy(gsc->dmat, fb_dmamap);
-fail4:
+fail5:
bus_dmamap_unload(gsc->dmat, tm_dmamap);
-fail3:
+fail4:
bus_dmamem_unmap(gsc->dmat, screen->tm, screen->tm_size);
-fail2:
+fail3:
bus_dmamem_free(gsc->dmat, tm_segs, tm_nsegs);
-fail1:
+fail2:
bus_dmamap_destroy(gsc->dmat, tm_dmamap);
+fail1:
+ bus_space_unmap(gsc->iot, gsc->re_ioh, RE_REG_SIZE);
fail0:
bus_space_unmap(gsc->iot, gsc->ioh, GBE_REG_SIZE);
}
@@ -383,11 +456,14 @@ gbe_init_screen(struct gbe_screen *screen)
int i;
/*
- * Initialise rasops.
+ * Initialise screen.
*/
+ screen->mode = WSDISPLAYIO_MODE_EMUL;
+
+ /* Initialise rasops. */
memset(&screen->ri, 0, sizeof(struct rasops_info));
- screen->ri.ri_flg = RI_CENTER | RI_CLEAR;
+ screen->ri.ri_flg = RI_CENTER;
screen->ri.ri_depth = screen->depth;
screen->ri.ri_width = screen->width;
screen->ri.ri_height = screen->height;
@@ -412,6 +488,28 @@ gbe_init_screen(struct gbe_screen *screen)
rasops_init(&screen->ri, screen->height / 8, screen->width / 8);
+ /* Create a rasops instance that can draw into a single tile. */
+ memcpy(&screen->ri_tile, &screen->ri, sizeof(struct rasops_info));
+ screen->ri_tile.ri_flg = 0;
+ screen->ri_tile.ri_width = GBE_TILE_WIDTH >> (screen->depth >> 4);
+ screen->ri_tile.ri_height = GBE_TILE_HEIGHT;
+ screen->ri_tile.ri_stride = screen->ri_tile.ri_width *
+ screen->depth / 8;
+ screen->ri_tile.ri_xorigin = 0;
+ screen->ri_tile.ri_yorigin = 0;
+ screen->ri_tile.ri_bits = screen->ro;
+ screen->ri_tile.ri_origbits = screen->ro;
+ screen->ro_curpos = 0;
+
+ screen->ri.ri_hw = screen->sc;
+
+ screen->ri.ri_do_cursor = gbe_do_cursor;
+ screen->ri.ri_ops.putchar = gbe_putchar;
+ screen->ri.ri_ops.copyrows = gbe_copyrows;
+ screen->ri.ri_ops.copycols = gbe_copycols;
+ screen->ri.ri_ops.eraserows = gbe_eraserows;
+ screen->ri.ri_ops.erasecols = gbe_erasecols;
+
gbe_stdscreen.ncols = screen->ri.ri_cols;
gbe_stdscreen.nrows = screen->ri.ri_rows;
gbe_stdscreen.textops = &screen->ri.ri_ops;
@@ -420,15 +518,16 @@ gbe_init_screen(struct gbe_screen *screen)
gbe_stdscreen.capabilities = screen->ri.ri_caps;
/*
- * Map framebuffer into tile map. Each entry in the tilemap is 16 bits
+ * Map framebuffer into tilemap. Each entry in the tilemap is 16 bits
* wide. Each tile is 64KB or 2^16 bits, hence the last 16 bits of the
* address will range from 0x0000 to 0xffff. As a result we simply
* discard the lower 16 bits and store bits 17 through 32 as an entry
* in the tilemap.
*/
tm = (void *)screen->tm;
- for (i = 0; i < (screen->fb_size >> GBE_TILE_SHIFT); i++)
- tm[i] = (screen->fb_phys >> GBE_TILE_SHIFT) + i;
+ for (i = 0; i < (screen->fb_size >> GBE_TILE_SHIFT) &&
+ i < GBE_TLB_SIZE; i++)
+ tm[i] = (screen->fb_phys >> GBE_TILE_SHIFT) + i;
}
void
@@ -462,7 +561,7 @@ gbe_enable(struct gbe_softc *gsc)
if (i == 10000)
printf("timeout unfreezing pixel counter!\n");
- /* Provide GBE with address of tile map and enable DMA. */
+ /* Provide GBE with address of tilemap and enable DMA. */
bus_space_write_4(gsc->iot, gsc->ioh, GBE_FB_CTRL,
((screen->tm_phys >> 9) <<
GBE_FB_CTRL_TILE_PTR_SHIFT) | GBE_FB_CTRL_DMA_ENABLE);
@@ -564,9 +663,11 @@ void
gbe_setup(struct gbe_softc *gsc)
{
struct gbe_screen *screen = gsc->curscr;
- uint32_t val;
- int i, cmode;
+ int i, t, cmode, tile_width, tiles_x, tiles_y;
u_char *colour;
+ uint16_t *tm;
+ uint32_t val;
+ uint64_t reg;
/*
* Setup framebuffer.
@@ -574,25 +675,69 @@ gbe_setup(struct gbe_softc *gsc)
switch (screen->depth) {
case 32:
cmode = GBE_CMODE_RGB8;
+ screen->bufmode = COLOUR_DEPTH_32 << BUFMODE_BUFDEPTH_SHIFT |
+ PIXEL_TYPE_RGB << BUFMODE_PIXTYPE_SHIFT |
+ COLOUR_DEPTH_32 << BUFMODE_PIXDEPTH_SHIFT;
break;
case 16:
cmode = GBE_CMODE_ARGB5;
+ screen->bufmode = COLOUR_DEPTH_16 << BUFMODE_BUFDEPTH_SHIFT |
+ PIXEL_TYPE_RGBA << BUFMODE_PIXTYPE_SHIFT |
+ COLOUR_DEPTH_16 << BUFMODE_PIXDEPTH_SHIFT;
break;
case 8:
default:
cmode = GBE_CMODE_I8;
+ screen->bufmode = COLOUR_DEPTH_8 << BUFMODE_BUFDEPTH_SHIFT |
+ PIXEL_TYPE_CI << BUFMODE_PIXTYPE_SHIFT |
+ COLOUR_DEPTH_8 << BUFMODE_PIXDEPTH_SHIFT;
break;
}
- /* Trick framebuffer into linear mode. */
- i = screen->width * screen->height / (512 / (screen->depth >> 3));
- bus_space_write_4(gsc->iot, gsc->ioh, GBE_FB_SIZE_PIXEL,
- i << GBE_FB_SIZE_PIXEL_HEIGHT_SHIFT);
+ /* Calculate tile width in bytes and screen size in tiles. */
+ tile_width = GBE_TILE_WIDTH >> (screen->depth >> 4);
+ tiles_x = (screen->width + tile_width - 1) >>
+ (GBE_TILE_WIDTH_SHIFT - (screen->depth >> 4));
+ tiles_y = (screen->height + GBE_TILE_HEIGHT - 1) >>
+ GBE_TILE_HEIGHT_SHIFT;
- bus_space_write_4(gsc->iot, gsc->ioh, GBE_FB_SIZE_TILE,
- (1 << GBE_FB_SIZE_TILE_WIDTH_SHIFT) |
- ((screen->depth >> 4) << GBE_FB_SIZE_TILE_DEPTH_SHIFT));
-
+ if (screen->mode != WSDISPLAYIO_MODE_EMUL) {
+
+ /*
+ * Setup the framebuffer in "linear" mode. We trick the
+ * framebuffer into linear mode by telling it that it is one
+ * tile wide and specifying an adjusted framebuffer height.
+ */
+
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_FB_SIZE_TILE,
+ ((screen->depth >> 4) << GBE_FB_SIZE_TILE_DEPTH_SHIFT) |
+ (1 << GBE_FB_SIZE_TILE_WIDTH_SHIFT));
+
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_FB_SIZE_PIXEL,
+ (screen->width * screen->height / tile_width) <<
+ GBE_FB_SIZE_PIXEL_HEIGHT_SHIFT);
+
+ } else {
+
+ /*
+ * Setup the framebuffer in tiled mode. Provide the tile
+ * colour depth, screen width in whole and partial tiles,
+ * and the framebuffer height in pixels.
+ */
+
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_FB_SIZE_TILE,
+ ((screen->depth >> 4) << GBE_FB_SIZE_TILE_DEPTH_SHIFT) |
+ ((screen->width / tile_width) <<
+ GBE_FB_SIZE_TILE_WIDTH_SHIFT) |
+ ((screen->width % tile_width != 0) ?
+ (screen->height / GBE_TILE_HEIGHT) : 0));
+
+ bus_space_write_4(gsc->iot, gsc->ioh, GBE_FB_SIZE_PIXEL,
+ screen->height << GBE_FB_SIZE_PIXEL_HEIGHT_SHIFT);
+
+ }
+
+ /* Set colour mode registers. */
val = (cmode << GBE_WID_MODE_SHIFT) | GBE_BMODE_BOTH;
for (i = 0; i < (32 * 4); i += 4)
bus_space_write_4(gsc->iot, gsc->ioh, GBE_MODE + i, val);
@@ -623,6 +768,56 @@ gbe_setup(struct gbe_softc *gsc)
GBE_GMAP + i * sizeof(u_int32_t),
(i << 24) | (i << 16) | (i << 8));
+ /*
+ * Initialise the rendering engine.
+ */
+ val = screen->mode | BUF_TYPE_TLB_A << BUFMODE_BUFTYPE_SHIFT;
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_BUFMODE_SRC, val);
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_BUFMODE_DST, val);
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_CLIPMODE, 0);
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_COLOUR_MASK, 0xffffffff);
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_PIXEL_XFER_X_STEP, 1);
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_PIXEL_XFER_Y_STEP, 1);
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_WINOFFSET_DST, 0);
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_WINOFFSET_SRC, 0);
+
+ /*
+ * Load framebuffer tiles into TLB A. Each TLB consists of a 16x16
+ * tile array representing 2048x2048 pixels. Each entry in the TLB
+ * consists of four 16-bit entries which represent bits 17:32 of the
+ * 64KB tile address. As a result, we can make use of the tilemap
+ * which already stores tile entries in the same format.
+ */
+ tm = (void *)screen->tm;
+ for (i = 0, t = 0; i < GBE_TLB_SIZE; i++) {
+ reg <<= 16;
+ if (i % 16 < tiles_x)
+ reg |= (tm[t++] | 0x8000);
+ if (i % 4 == 3)
+ bus_space_write_8(gsc->iot, gsc->re_ioh,
+ RE_TLB_A + (i >> 2) * 8, reg);
+ }
+
+ /* Load single tile into TLB B for rasops. */
+ bus_space_write_8(gsc->iot, gsc->re_ioh,
+ RE_TLB_B, (screen->ro_phys >> 16 | 0x8000) << 48);
+}
+
+void
+gbe_wait_re_idle(struct gbe_softc *gsc)
+{
+ int i;
+
+ /* Wait until rendering engine is idle. */
+ for (i = 0; i < 100000; i++) {
+ if (bus_space_read_4(gsc->iot, gsc->re_ioh, RE_PP_STATUS) &
+ RE_PP_STATUS_IDLE)
+ break;
+ delay(1);
+ }
+ if (i == 100000)
+ printf("%s: rendering engine did not become idle!\n",
+ gsc->sc_dev.dv_xname);
}
/*
@@ -633,7 +828,7 @@ int
gbe_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
{
struct gbe_screen *screen = (struct gbe_screen *)v;
- int rc;
+ int rc, mode;
switch (cmd) {
case WSDISPLAYIO_GTYPE:
@@ -678,6 +873,29 @@ gbe_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
}
break;
+ case WSDISPLAYIO_GMODE:
+ *(u_int *)data = screen->mode;
+ break;
+
+ case WSDISPLAYIO_SMODE:
+ mode = *(u_int *)data;
+ if (mode == WSDISPLAYIO_MODE_EMUL ||
+ mode == WSDISPLAYIO_MODE_MAPPED ||
+ mode == WSDISPLAYIO_MODE_DUMBFB) {
+
+ screen->mode = mode;
+
+ gbe_disable((struct gbe_softc *)screen->sc);
+ gbe_setup((struct gbe_softc *)screen->sc);
+ gbe_enable((struct gbe_softc *)screen->sc);
+
+ /* Clear framebuffer if entering emulated mode. */
+ if (screen->mode == WSDISPLAYIO_MODE_EMUL)
+ gbe_fillrect((struct gbe_softc *)screen->sc,
+ 0, 0, screen->width, screen->height, 0);
+ }
+ break;
+
case WSDISPLAYIO_GVIDEO:
case WSDISPLAYIO_SVIDEO:
/* Handled by the upper layer. */
@@ -824,6 +1042,215 @@ gbe_loadcmap(struct gbe_screen *screen, u_int start, u_int end)
}
/*
+ * Hardware accelerated functions for rasops.
+ */
+
+void
+gbe_rop(struct gbe_softc *gsc, int x, int y, int w, int h, int op)
+{
+
+ gbe_wait_re_idle(gsc);
+
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_PRIMITIVE,
+ PRIMITIVE_RECTANGLE | PRIMITIVE_LRTB);
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_DRAWMODE,
+ DRAWMODE_BITMASK | DRAWMODE_BYTEMASK | DRAWMODE_PIXEL_XFER |
+ DRAWMODE_LOGIC_OP);
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_LOGIC_OP, op);
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_PIXEL_XFER_SRC,
+ (x << 16) | (y & 0xffff));
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_VERTEX_X_0,
+ (x << 16) | (y & 0xffff));
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_VERTEX_X_1 | RE_START,
+ ((x + w - 1) << 16) | ((y + h - 1) & 0xffff));
+}
+
+void
+gbe_copyrect(struct gbe_softc *gsc, int src, int sx, int sy, int dx, int dy,
+ int w, int h)
+{
+ int direction, x0, y0, x1, y1;
+
+ if (sx >= dx && sy >= dy) {
+ direction = PRIMITIVE_LRTB;
+ x0 = dx;
+ y0 = dy;
+ x1 = dx + w - 1;
+ y1 = dy + h - 1;
+ } else if (sx >= dx && sy < dy) {
+ direction = PRIMITIVE_LRBT;
+ sy = sy + h - 1;
+ x0 = dx;
+ y0 = dy + h - 1;
+ x1 = dx + w - 1;
+ y1 = dy;
+ } else if (sx < dx && sy >= dy) {
+ direction = PRIMITIVE_RLTB;
+ sx = sx + w - 1;
+ x0 = dx + w - 1;
+ y0 = dy;
+ x1 = dx;
+ y1 = dy + h - 1;
+ } else if (sx < dx && sy < dy) {
+ direction = PRIMITIVE_RLBT;
+ sy = sy + h - 1;
+ sx = sx + w - 1;
+ x0 = dx + w - 1;
+ y0 = dy + h - 1;
+ x1 = dx;
+ y1 = dy;
+ }
+
+ gbe_wait_re_idle(gsc);
+
+ if (src != BUF_TYPE_TLB_A)
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_BUFMODE_SRC,
+ gsc->curscr->bufmode | (src << BUFMODE_BUFTYPE_SHIFT));
+
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_PRIMITIVE,
+ PRIMITIVE_RECTANGLE | direction);
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_DRAWMODE,
+ DRAWMODE_BITMASK | DRAWMODE_BYTEMASK | DRAWMODE_PIXEL_XFER);
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_PIXEL_XFER_SRC,
+ (sx << 16) | (sy & 0xffff));
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_VERTEX_X_0,
+ (x0 << 16) | (y0 & 0xffff));
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_VERTEX_X_1 | RE_START,
+ (x1 << 16) | (y1 & 0xffff));
+
+ if (src != BUF_TYPE_TLB_A) {
+ gbe_wait_re_idle(gsc);
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_BUFMODE_SRC,
+ gsc->curscr->bufmode |
+ (BUF_TYPE_TLB_A << BUFMODE_BUFTYPE_SHIFT));
+ }
+}
+
+void
+gbe_fillrect(struct gbe_softc *gsc, int x, int y, int w, int h, int bg)
+{
+
+ gbe_wait_re_idle(gsc);
+
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_PRIMITIVE,
+ PRIMITIVE_RECTANGLE | PRIMITIVE_LRTB);
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_DRAWMODE,
+ DRAWMODE_BITMASK | DRAWMODE_BYTEMASK);
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_SHADE_FG_COLOUR, bg);
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_VERTEX_X_0,
+ (x << 16) | (y & 0xffff));
+ bus_space_write_4(gsc->iot, gsc->re_ioh, RE_PP_VERTEX_X_1 | RE_START,
+ ((x + w - 1) << 16) | ((y + h - 1) & 0xffff));
+}
+
+void
+gbe_do_cursor(struct rasops_info *ri)
+{
+ struct gbe_softc *sc = ri->ri_hw;
+ int y, x, w, h;
+
+ w = ri->ri_font->fontwidth;
+ h = ri->ri_font->fontheight;
+ x = ri->ri_xorigin + ri->ri_ccol * w;
+ y = ri->ri_yorigin + ri->ri_crow * h;
+
+ gbe_rop(sc, x, y, w, h, LOGIC_OP_XOR);
+}
+
+void
+gbe_putchar(void *cookie, int row, int col, u_int uc, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct gbe_softc *gsc = ri->ri_hw;
+ struct gbe_screen *screen = gsc->curscr;
+ struct rasops_info *ri_tile = &screen->ri_tile;
+ int x, y, w, h;
+
+ w = ri->ri_font->fontwidth;
+ h = ri->ri_font->fontheight;
+ x = ri->ri_xorigin + col * w;
+ y = ri->ri_yorigin + row * h;
+
+ ri_tile->ri_ops.putchar(ri_tile, 0, screen->ro_curpos, uc, attr);
+
+ gbe_copyrect(gsc, BUF_TYPE_TLB_B, screen->ro_curpos * w, 0, x, y, w, h);
+
+ screen->ro_curpos++;
+ if ((screen->ro_curpos + 1) * w > screen->ri_tile.ri_width)
+ screen->ro_curpos = 0;
+}
+
+void
+gbe_copycols(void *cookie, int row, int src, int dst, int num)
+{
+ struct rasops_info *ri = cookie;
+ struct gbe_softc *sc = ri->ri_hw;
+
+ num *= ri->ri_font->fontwidth;
+ src *= ri->ri_font->fontwidth;
+ dst *= ri->ri_font->fontwidth;
+ row *= ri->ri_font->fontheight;
+
+ gbe_copyrect(sc, BUF_TYPE_TLB_A, ri->ri_xorigin + src,
+ ri->ri_yorigin + row, ri->ri_xorigin + dst, ri->ri_yorigin + row,
+ num, ri->ri_font->fontheight);
+}
+
+void
+gbe_erasecols(void *cookie, int row, int col, int num, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct gbe_softc *sc = ri->ri_hw;
+ int bg, fg;
+
+ ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
+
+ row *= ri->ri_font->fontheight;
+ col *= ri->ri_font->fontwidth;
+ num *= ri->ri_font->fontwidth;
+
+ gbe_fillrect(sc, ri->ri_xorigin + col, ri->ri_yorigin + row,
+ num, ri->ri_font->fontheight, ri->ri_devcmap[bg]);
+}
+
+void
+gbe_copyrows(void *cookie, int src, int dst, int num)
+{
+ struct rasops_info *ri = cookie;
+ struct gbe_softc *sc = ri->ri_hw;
+
+ num *= ri->ri_font->fontheight;
+ src *= ri->ri_font->fontheight;
+ dst *= ri->ri_font->fontheight;
+
+ gbe_copyrect(sc, BUF_TYPE_TLB_A, ri->ri_xorigin, ri->ri_yorigin + src,
+ ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num);
+}
+
+void
+gbe_eraserows(void *cookie, int row, int num, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct gbe_softc *sc = ri->ri_hw;
+ int x, y, w, bg, fg;
+
+ ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
+
+ if ((num == ri->ri_rows) && ISSET(ri->ri_flg, RI_FULLCLEAR)) {
+ num = ri->ri_height;
+ x = y = 0;
+ w = ri->ri_width;
+ } else {
+ num *= ri->ri_font->fontheight;
+ x = ri->ri_xorigin;
+ y = ri->ri_yorigin + row * ri->ri_font->fontheight;
+ w = ri->ri_emuwidth;
+ }
+
+ gbe_fillrect(sc, x, y, w, num, ri->ri_devcmap[bg]);
+}
+
+/*
* Console functions for early display.
*/
@@ -852,29 +1279,32 @@ gbe_cnprobe(bus_space_tag_t iot, bus_addr_t addr)
int
gbe_cnattach(bus_space_tag_t iot, bus_addr_t addr)
{
- struct gbe_softc gsc;
- vaddr_t va;
- paddr_t pa;
+ struct gbe_softc *gsc;
uint32_t val;
+ paddr_t pa;
+ vaddr_t va;
long attr;
/*
* Setup GBE for use as early console.
*/
- gsc.curscr = &gbe_consdata;
- gbe_consdata.sc = (void *)&gsc;
+ va = pmap_steal_memory(sizeof(struct gbe_softc), NULL, NULL);
+ gsc = (struct gbe_softc *)va;
+ gsc->curscr = &gbe_consdata;
+ gbe_consdata.sc = (struct device *)gsc;
/* Setup bus space mapping. */
- gsc.iot = iot;
- gsc.ioh = PHYS_TO_UNCACHED(addr);
+ gsc->iot = iot;
+ gsc->ioh = PHYS_TO_UNCACHED(addr);
+ gsc->re_ioh = PHYS_TO_UNCACHED(RE_BASE);
/* Determine GBE revision. */
- gsc.rev = bus_space_read_4(gsc.iot, gsc.ioh, GBE_CTRL_STAT) & 0xf;
+ gsc->rev = bus_space_read_4(gsc->iot, gsc->ioh, GBE_CTRL_STAT) & 0xf;
/* Determine resolution configured by firmware. */
- val = bus_space_read_4(gsc.iot, gsc.ioh, GBE_VT_HCMAP);
+ val = bus_space_read_4(gsc->iot, gsc->ioh, GBE_VT_HCMAP);
gbe_consdata.width = (val >> GBE_VT_HCMAP_ON_SHIFT) & 0xfff;
- val = bus_space_read_4(gsc.iot, gsc.ioh, GBE_VT_VCMAP);
+ val = bus_space_read_4(gsc->iot, gsc->ioh, GBE_VT_VCMAP);
gbe_consdata.height = (val >> GBE_VT_VCMAP_ON_SHIFT) & 0xfff;
/* Ensure that the firmware has setup the device. */
@@ -903,18 +1333,29 @@ gbe_cnattach(bus_space_tag_t iot, bus_addr_t addr)
gbe_consdata.fb_phys = ((pa >> 16) + 1) << 16;
gbe_consdata.fb = (caddr_t)PHYS_TO_UNCACHED(gbe_consdata.fb_phys);
+ /*
+ * Steal memory for rasops tile - 64KB aligned and coherent.
+ */
+ va = pmap_steal_memory(GBE_TILE_SIZE + 65536, NULL, NULL);
+ pmap_extract(pmap_kernel(), va, &pa);
+ gbe_consdata.ro_phys = ((pa >> 16) + 1) << 16;
+ gbe_consdata.ro = (caddr_t)PHYS_TO_UNCACHED(gbe_consdata.ro_phys);
+
/*
* Setup GBE hardware.
*/
gbe_init_screen(&gbe_consdata);
- gbe_disable(&gsc);
- gbe_setup(&gsc);
- gbe_enable(&gsc);
+ gbe_disable(gsc);
+ gbe_setup(gsc);
+ gbe_enable(gsc);
/* Load colourmap if required. */
if (gbe_consdata.depth == 8)
gbe_loadcmap(&gbe_consdata, 0, 255);
+ /* Clear framebuffer. */
+ gbe_fillrect(gsc, 0, 0, gbe_consdata.width, gbe_consdata.height, 0);
+
/*
* Attach wsdisplay.
*/