diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2011-12-30 12:47:21 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2011-12-30 12:47:21 +0000 |
commit | 9f866067119813243c2e8ecd757d376e74c5d8a6 (patch) | |
tree | ec7af41e567cda37a436e90f996c2bfcfd492c7a /sys/arch/hp300 | |
parent | f5a79a196e245d6be44d5aee982af2703193d6fc (diff) |
I had the opportunity to glance at HP-UX's /etc/conf/graf/gr_98705.h, so
after hours of tinkering with my frame buffer debugger, here comes color
support for tvrx(4) - by making use of all overlay planes. Access to the
regular planes remains a mystery, and seems to require a download of
microcode into the board first. Still slightly better...
Diffstat (limited to 'sys/arch/hp300')
-rw-r--r-- | sys/arch/hp300/dev/tvrx.c | 231 |
1 files changed, 209 insertions, 22 deletions
diff --git a/sys/arch/hp300/dev/tvrx.c b/sys/arch/hp300/dev/tvrx.c index 0c65745917c..2772412a437 100644 --- a/sys/arch/hp300/dev/tvrx.c +++ b/sys/arch/hp300/dev/tvrx.c @@ -1,7 +1,7 @@ -/* $OpenBSD: tvrx.c,v 1.1 2006/04/14 21:05:43 miod Exp $ */ +/* $OpenBSD: tvrx.c,v 1.2 2011/12/30 12:47:19 miod Exp $ */ /* - * Copyright (c) 2006, Miodrag Vallat. + * Copyright (c) 2006, 2011, Miodrag Vallat. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,7 +28,9 @@ */ /* - * Graphics routines for the TurboVRX frame buffer + * Graphics routines for the ``TigerShark'' PersonalVRX frame buffer, + * in its non-STI flavour (DIO-II 98702-66501 interface board; the SGC + * 98705-66582 board is expected to be supported by the sti(4) driver). */ #include <sys/param.h> @@ -55,11 +57,60 @@ #include <hp300/dev/diofbreg.h> #include <hp300/dev/diofbvar.h> +/* + * Hardware registers + */ + +#define TVRX_FV_TRIG 0x5003 /* commit mode settings */ +#define TVRX_DISPLAY_ENABLE 0x500f /* enable display */ +#define TVRX_FB_P_ENABLE 0x5017 /* enable primary fb planes */ +#define TVRX_FB_S_ENABLE 0x501b /* enable secondary fb planes */ +#define TVRX_O_P_ENABLE 0x5023 /* enable primary overlay planes */ +#define TVRX_O_S_ENABLE 0x5027 /* enable secondary overlay planes */ +#define TVRX_WBUSY 0x7047 /* window mover busy */ +#define TVRX_ZHERE 0x7053 /* Z buffer available */ +#define TVRX_FB_WEN 0x7093 /* fb planes write enable */ +#define TVRX_WMOVE 0x709f /* trigger window mover */ +#define TVRX_O_WEN 0x70b7 /* overlay planes write enable */ +#define TVRX_DRIVE 0x70bf /* vram access mode */ +#define DRIVE_OVERLAY_ENABLE 0x10 /* drive vram to overlays */ +#define DRIVE_1BPP 0x80 /* force 1bpp packed memory */ +#define DRIVE_PLANE_MASK 0x0f /* overlay planes read mask */ +#define TVRX_REP_RULE 0x70ef /* window mover replacement rule */ +#define TVRX_ROP(rop) ((rop) << 4 | (rop)) +#define TVRX_SRC_X 0x70f2 /* window mover source position */ +#define TVRX_SRC_Y 0x70f6 +#define TVRX_DST_X 0x70fa /* window mover destination position */ +#define TVRX_DST_Y 0x70fe +#define TVRX_CNT_X 0x7102 /* window mover span */ +#define TVRX_CNT_Y 0x7106 + +#define TVRX_CMAP_O_P 0x5203 /* primary overlay colormap (16xRGB) */ +#define TVRX_CMAP_O_S 0x5303 /* secondary overlay colormap */ +#define TVRX_CMAP_FB_P_R 0x5403 /* primary fb colormap, 256xR */ +#define TVRX_CMAP_FB_P_G 0x5803 /* primary fb colormap, 256xG */ +#define TVRX_CMAP_FB_P_B 0x5c03 /* primary fb colormap, 256xB */ +#define TVRX_CMAP_FB_S_R 0x6403 /* secondary fb colormap, 256xR */ +#define TVRX_CMAP_FB_S_G 0x6803 /* secondary fb colormap, 256xG */ +#define TVRX_CMAP_FB_S_B 0x6c03 /* secondary fb colormap, 256xB */ + +#define tvrx_reg(kva,type,offset) \ + (*(volatile type *)((kva) + (offset))) + +/* wait for window mover to become idle */ +#define tvrx_waitbusy(fb) \ +do { \ + while (tvrx_reg((fb)->regkva, uint8_t, TVRX_WBUSY) & 0x01) \ + ; \ +} while (0) + + struct tvrx_softc { - struct device sc_dev; - struct diofb *sc_fb; - struct diofb sc_fb_store; - int sc_scode; + struct device sc_dev; + struct diofb *sc_fb; + struct diofb sc_fb_store; + + int sc_scode; }; int tvrx_match(struct device *, void *, void *); @@ -74,8 +125,14 @@ struct cfdriver tvrx_cd = { }; int tvrx_reset(struct diofb *, int, struct diofbreg *); +void tvrx_restore(struct diofb *); +int tvrx_setcmap(struct diofb *, struct wsdisplay_cmap *); +void tvrx_setcolor(struct diofb *, u_int); +int tvrx_windowmove(struct diofb *, u_int16_t, u_int16_t, u_int16_t, + u_int16_t, u_int16_t, u_int16_t, int16_t, int16_t); int tvrx_ioctl(void *, u_long, caddr_t, int, struct proc *); +void tvrx_burner(void *, u_int, u_int); struct wsdisplay_accessops tvrx_accessops = { tvrx_ioctl, @@ -86,7 +143,7 @@ struct wsdisplay_accessops tvrx_accessops = { NULL, /* load_font */ NULL, /* scrollback */ NULL, /* getchar */ - NULL /* burner */ + tvrx_burner }; /* @@ -138,31 +195,60 @@ int tvrx_reset(struct diofb *fb, int scode, struct diofbreg *fbr) { int rc; + u_int i; if ((rc = diofb_fbinquire(fb, scode, fbr)) != 0) return (rc); - /* - * We rely on the PROM to initialize the frame buffer in the mode - * we expect it: cleared, overlay plane enabled and accessible - * at the beginning of the video memory. - * - * This is NOT the mode we would end up by simply resetting the - * board. - */ + /* diofb_fbinquire will return 8 (or maybe 16) planes, but we + only use the 4 overlay planes */ + fb->planes = 4; + fb->planemask = (1 << 4) - 1; - fb->ri.ri_depth = 1; - fb->bmv = diofb_mono_windowmove; + fb->bmv = tvrx_windowmove; + tvrx_restore(fb); diofb_fbsetup(fb); + for (i = 0; i <= fb->planemask; i++) + tvrx_setcolor(fb, i); return (0); } +void +tvrx_restore(struct diofb *fb) +{ + volatile struct diofbreg *fbr = (volatile struct diofbreg *)fb->regkva; + + /* + * Resetting the hardware is slow, disables display output, and + * does not clear video memory. Give it some time before we setup + * ourselves. + */ + fbr->id = GRFHWID; + DELAY(100000); + + /* run the overlay planes unpacked... */ + tvrx_reg(fb->regkva, uint8_t, TVRX_DRIVE) = + DRIVE_OVERLAY_ENABLE | fb->planemask; + /* ...and enable the four of them */ + tvrx_reg(fb->regkva, uint8_t, TVRX_O_P_ENABLE) = fb->planemask; + tvrx_reg(fb->regkva, uint8_t, TVRX_O_S_ENABLE) = fb->planemask; + tvrx_reg(fb->regkva, uint8_t, TVRX_O_WEN) = fb->planemask; + /* disable fb planes for safety */ + tvrx_reg(fb->regkva, uint8_t, TVRX_FB_P_ENABLE) = 0; + tvrx_reg(fb->regkva, uint8_t, TVRX_FB_S_ENABLE) = 0; + + tvrx_reg(fb->regkva, uint8_t, TVRX_REP_RULE) = TVRX_ROP(RR_COPY); + tvrx_reg(fb->regkva, uint8_t, TVRX_DISPLAY_ENABLE) = 0x01; + tvrx_reg(fb->regkva, uint8_t, TVRX_FV_TRIG) = 0x01; +} + int tvrx_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p) { struct diofb *fb = v; struct wsdisplay_fbinfo *wdf; + u_int i; switch (cmd) { case WSDISPLAYIO_GTYPE: @@ -170,24 +256,34 @@ tvrx_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p) break; case WSDISPLAYIO_SMODE: fb->mapmode = *(u_int *)data; + if (fb->mapmode == WSDISPLAYIO_MODE_EMUL) { + tvrx_restore(fb); + /* clear display */ + (*fb->bmv)(fb, 0, 0, 0, 0, fb->fbwidth, fb->fbheight, + RR_CLEAR, fb->planemask); + /* restore colormap */ + diofb_resetcmap(fb); + for (i = 0; i <= fb->planemask; i++) + tvrx_setcolor(fb, i); + } break; case WSDISPLAYIO_GINFO: wdf = (void *)data; wdf->width = fb->ri.ri_width; wdf->height = fb->ri.ri_height; wdf->depth = fb->ri.ri_depth; - wdf->cmsize = 0; + wdf->cmsize = 1 << fb->planes; break; case WSDISPLAYIO_LINEBYTES: *(u_int *)data = fb->ri.ri_stride; break; case WSDISPLAYIO_GETCMAP: + return (diofb_getcmap(fb, (struct wsdisplay_cmap *)data)); case WSDISPLAYIO_PUTCMAP: - break; /* until color support is implemented */ + return (tvrx_setcmap(fb, (struct wsdisplay_cmap *)data)); case WSDISPLAYIO_GVIDEO: case WSDISPLAYIO_SVIDEO: - /* unsupported */ - return (-1); + break; default: return (-1); } @@ -195,6 +291,97 @@ tvrx_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p) return (0); } +void +tvrx_burner(void *v, u_int on, u_int flags) +{ + struct diofb *fb = v; + + tvrx_reg(fb->regkva, uint8_t, TVRX_DISPLAY_ENABLE) = on ? 0x01 : 0x00; + tvrx_reg(fb->regkva, uint8_t, TVRX_FV_TRIG) = 0x01; +} + +void +tvrx_setcolor(struct diofb *fb, u_int index) +{ + u_int index_scaled = index * 3 * 4; + + tvrx_reg(fb->regkva, uint8_t, TVRX_CMAP_O_P + index_scaled) = + tvrx_reg(fb->regkva, uint8_t, TVRX_CMAP_O_S + index_scaled) = + fb->cmap.r[index]; + tvrx_reg(fb->regkva, uint8_t, TVRX_CMAP_O_P + 4 + index_scaled) = + tvrx_reg(fb->regkva, uint8_t, TVRX_CMAP_O_S + 4 + index_scaled) = + fb->cmap.g[index]; + tvrx_reg(fb->regkva, uint8_t, TVRX_CMAP_O_P + 2 * 4 + index_scaled) = + tvrx_reg(fb->regkva, uint8_t, TVRX_CMAP_O_S + 2 * 4 + index_scaled) = + fb->cmap.b[index]; +} + +int +tvrx_setcmap(struct diofb *fb, struct wsdisplay_cmap *cm) +{ + u_int8_t r[256], g[256], b[256]; + u_int index = cm->index, count = cm->count; + u_int colcount = 1 << fb->planes; + int error; + + if (index >= colcount || count > colcount - index) + return (EINVAL); + + if ((error = copyin(cm->red, r, count)) != 0) + return (error); + if ((error = copyin(cm->green, g, count)) != 0) + return (error); + if ((error = copyin(cm->blue, b, count)) != 0) + return (error); + + bcopy(r, fb->cmap.r + index, count); + bcopy(g, fb->cmap.g + index, count); + bcopy(b, fb->cmap.b + index, count); + + while (count-- != 0) + tvrx_setcolor(fb, index++); + + return (0); +} + +int +tvrx_windowmove(struct diofb *fb, u_int16_t sx, u_int16_t sy, u_int16_t dx, + u_int16_t dy, u_int16_t cx, u_int16_t cy, int16_t rop, int16_t planemask) +{ +#ifdef TVRX_DEBUG + printf("%s: %dx%d %dx%d %dx%d rx %x planemask %x\n", + __func__, fb->sx, sy, dx, dy, cx, cy, rop, planemask); +#endif + + planemask &= fb->planemask; + + tvrx_reg(fb->regkva, uint16_t, TVRX_SRC_Y) = sy; + tvrx_reg(fb->regkva, uint16_t, TVRX_SRC_X) = sx; + tvrx_reg(fb->regkva, uint16_t, TVRX_DST_Y) = dy; + tvrx_reg(fb->regkva, uint16_t, TVRX_DST_X) = dx; + tvrx_reg(fb->regkva, uint16_t, TVRX_CNT_Y) = cy; + tvrx_reg(fb->regkva, uint16_t, TVRX_CNT_X) = cx; + + tvrx_reg(fb->regkva, uint8_t, TVRX_REP_RULE) = TVRX_ROP(rop); + tvrx_reg(fb->regkva, uint8_t, TVRX_O_WEN) = planemask; + tvrx_reg(fb->regkva, uint8_t, TVRX_WMOVE) = 1; + tvrx_waitbusy(fb); + + if (planemask != fb->planemask) { + rop ^= 0x0f; + planemask ^= fb->planemask; + tvrx_reg(fb->regkva, uint8_t, TVRX_REP_RULE) = TVRX_ROP(rop); + tvrx_reg(fb->regkva, uint8_t, TVRX_O_WEN) = planemask; + tvrx_reg(fb->regkva, uint8_t, TVRX_WMOVE) = 1; + tvrx_waitbusy(fb); + } + + tvrx_reg(fb->regkva, uint8_t, TVRX_O_WEN) = fb->planemask; + tvrx_reg(fb->regkva, uint8_t, TVRX_REP_RULE) = TVRX_ROP(RR_COPY); + + return 0; +} + /* * Console support */ |