support screen blanking and hw cursor

This commit is contained in:
macallan 2016-02-11 20:53:06 +00:00
parent 6af8d6733f
commit 55009e9dd3
2 changed files with 189 additions and 11 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: mgx.c,v 1.5 2016/02/11 02:23:44 macallan Exp $ */
/* $NetBSD: mgx.c,v 1.6 2016/02/11 20:53:06 macallan Exp $ */
/*-
* Copyright (c) 2014 Michael Lorenz
@ -29,7 +29,7 @@
/* a console driver for the SSB 4096V-MGX graphics card */
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mgx.c,v 1.5 2016/02/11 02:23:44 macallan Exp $");
__KERNEL_RCSID(0, "$NetBSD: mgx.c,v 1.6 2016/02/11 20:53:06 macallan Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -67,6 +67,7 @@ struct mgx_softc {
bus_space_handle_t sc_vgah;
bus_addr_t sc_paddr;
void *sc_fbaddr;
uint8_t *sc_cursor;
int sc_width;
int sc_height;
int sc_stride;
@ -78,6 +79,9 @@ struct mgx_softc {
u_char sc_cmap_red[256];
u_char sc_cmap_green[256];
u_char sc_cmap_blue[256];
int sc_cursor_x, sc_cursor_y;
int sc_hotspot_x, sc_hotspot_y;
int sc_video;
void (*sc_putchar)(void *, int, int, u_int, long);
struct vcons_screen sc_console_screen;
struct wsscreen_descr sc_defaultscreen_descr;
@ -113,6 +117,10 @@ static void mgx_erasecols(void *, int, int, int, long);
static void mgx_copyrows(void *, int, int, int);
static void mgx_eraserows(void *, int, int, long);
static int mgx_do_cursor(struct mgx_softc *, struct wsdisplay_cursor *);
static void mgx_set_cursor(struct mgx_softc *);
static void mgx_set_video(struct mgx_softc *, int);
CFATTACH_DECL_NEW(mgx, sizeof(struct mgx_softc),
mgx_match, mgx_attach, NULL, NULL);
@ -151,6 +159,12 @@ mgx_read_1(struct mgx_softc *sc, uint32_t reg)
return bus_space_read_1(sc->sc_tag, sc->sc_blith, reg ^ 3);
}
static inline void
mgx_write_2(struct mgx_softc *sc, uint32_t reg, uint16_t val)
{
bus_space_write_2(sc->sc_tag, sc->sc_blith, reg ^ 2, val);
}
static inline void
mgx_write_4(struct mgx_softc *sc, uint32_t reg, uint32_t val)
{
@ -240,6 +254,13 @@ mgx_attach(device_t parent, device_t self, void *args)
WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
NULL
};
sc->sc_cursor_x = 0;
sc->sc_cursor_y = 0;
sc->sc_hotspot_x = 0;
sc->sc_hotspot_y = 0;
sc->sc_video = WSDISPLAYIO_VIDEO_ON;
sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
@ -526,6 +547,17 @@ mgx_setup(struct mgx_softc *sc, int depth)
mgx_write_vga(sc, CRTC_DATA, stride & 0xff);
mgx_write_vga(sc, CRTC_INDEX, 0x1c);
mgx_write_vga(sc, CRTC_DATA, (stride & 0xf00) >> 4);
/* clean up the screen if we're switching to != 8bit */
if (depth != MGX_DEPTH)
mgx_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, 0);
/* initialize hardware cursor stuff */
mgx_write_2(sc, ATR_CURSOR_ADDRESS, (sc->sc_fbsize - 1024) >> 10);
mgx_write_1(sc, ATR_CURSOR_ENABLE, 0);
sc->sc_cursor = (uint8_t *)sc->sc_fbaddr + sc->sc_fbsize - 1024;
memset(sc->sc_cursor, 0xf0, 1024);
#ifdef MGX_DEBUG
int j;
mgx_write_vga(sc, SEQ_INDEX, 0x10);
@ -812,11 +844,12 @@ mgx_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
case FBIOGVIDEO:
case WSDISPLAYIO_GVIDEO:
*(int *)data = 1;
*(int *)data = sc->sc_video;
return 0;
case WSDISPLAYIO_SVIDEO:
case FBIOSVIDEO:
mgx_set_video(sc, *(int *)data);
return 0;
case WSDISPLAYIO_LINEBYTES:
@ -852,11 +885,45 @@ mgx_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
case WSDISPLAYIO_PUTCMAP:
return mgx_putcmap(sc, (struct wsdisplay_cmap *)data);
case WSDISPLAYIO_GCURPOS:
{
struct wsdisplay_curpos *cp = (void *)data;
cp->x = sc->sc_cursor_x;
cp->y = sc->sc_cursor_y;
}
return 0;
case WSDISPLAYIO_SCURPOS:
{
struct wsdisplay_curpos *cp = (void *)data;
sc->sc_cursor_x = cp->x;
sc->sc_cursor_y = cp->y;
mgx_set_cursor(sc);
}
return 0;
case WSDISPLAYIO_GCURMAX:
{
struct wsdisplay_curpos *cp = (void *)data;
cp->x = 64;
cp->y = 64;
}
return 0;
case WSDISPLAYIO_SCURSOR:
{
struct wsdisplay_cursor *cursor = (void *)data;
return mgx_do_cursor(sc, cursor);
}
case WSDISPLAYIO_GET_FBINFO:
{
struct wsdisplayio_fbinfo *fbi = data;
fbi->fbi_fbsize = sc->sc_fbsize;
fbi->fbi_fbsize = sc->sc_fbsize - 1024;
fbi->fbi_width = sc->sc_width;
fbi->fbi_height = sc->sc_height;
fbi->fbi_bitsperpixel = sc->sc_depth;
@ -890,3 +957,113 @@ mgx_mmap(void *v, void *vs, off_t offset, int prot)
return -1;
}
static int
mgx_do_cursor(struct mgx_softc *sc, struct wsdisplay_cursor *cur)
{
int i;
if (cur->which & WSDISPLAY_CURSOR_DOCUR) {
if (cur->enable) {
mgx_set_cursor(sc);
mgx_write_1(sc, ATR_CURSOR_ENABLE, 1);
} else {
mgx_write_1(sc, ATR_CURSOR_ENABLE, 0);
}
}
if (cur->which & WSDISPLAY_CURSOR_DOHOT) {
sc->sc_hotspot_x = cur->hot.x;
sc->sc_hotspot_y = cur->hot.y;
mgx_set_cursor(sc);
}
if (cur->which & WSDISPLAY_CURSOR_DOPOS) {
sc->sc_cursor_x = cur->pos.x;
sc->sc_cursor_y = cur->pos.y;
mgx_set_cursor(sc);
}
if (cur->which & WSDISPLAY_CURSOR_DOCMAP) {
int cnt = min(2, cur->cmap.count);
uint8_t c;
uint8_t r[2], g[2], b[2];
copyin(cur->cmap.red, r, cnt);
copyin(cur->cmap.green, g, cnt);
copyin(cur->cmap.blue, b, cnt);
for (i = 0; i < cnt; i++) {
c = r[i] & 0xe0;
c |= (g[i] & 0xe0) >> 3;
c |= (b[i] & 0xc0) >> 6;
mgx_write_1(sc, ATR_CURSOR_FG + i, c);
}
}
if (cur->which & WSDISPLAY_CURSOR_DOSHAPE) {
int j;
uint8_t *fb = sc->sc_cursor;
uint8_t temp;
uint8_t im, ma, px;
for (i = 0; i < 512; i++) {
temp = 0;
copyin(&cur->image[i], &im, 1);
copyin(&cur->mask[i], &ma, 1);
for (j = 0; j < 4; j++) {
temp >>= 2;
px = (ma & 1) ? 0 : 0x80;
if (px == 0)
px |= (im & 1) ? 0 : 0x40;
temp |= px;
im >>= 1;
ma >>= 1;
}
*fb = temp;
fb++;
temp = 0;
for (j = 0; j < 4; j++) {
temp >>= 2;
px = (ma & 1) ? 0 : 0x80;
if (px == 0)
px |= (im & 1) ? 0 : 0x40;
temp |= px;
im >>= 1;
ma >>= 1;
}
*fb = temp;
fb++;
}
}
return 0;
}
static void
mgx_set_cursor(struct mgx_softc *sc)
{
uint32_t reg;
uint16_t hot;
reg = (sc->sc_cursor_y << 16) | (sc->sc_cursor_x & 0xffff);
mgx_write_4(sc, ATR_CURSOR_POSITION, reg);
hot = (sc->sc_hotspot_y << 8) | (sc->sc_hotspot_x & 0xff);
mgx_write_2(sc, ATR_CURSOR_HOTSPOT, hot);
}
static void
mgx_set_video(struct mgx_softc *sc, int v)
{
uint8_t reg;
if (sc->sc_video == v)
return;
sc->sc_video = v;
reg = mgx_read_1(sc, ATR_DPMS);
if (v == WSDISPLAYIO_VIDEO_ON) {
reg &= ~DPMS_SYNC_DISABLE_ALL;
} else {
reg |= DPMS_SYNC_DISABLE_ALL;
}
mgx_write_1(sc, ATR_DPMS, reg);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: mgxreg.h,v 1.3 2016/02/11 02:23:44 macallan Exp $ */
/* $NetBSD: mgxreg.h,v 1.4 2016/02/11 20:53:06 macallan Exp $ */
/* register definitions based on OpenBSD's atxxreg.h: */
@ -178,6 +178,7 @@
#define ATR_DPMS 0x00d0 /* byte access */
#define DPMS_HSYNC_DISABLE 0x01
#define DPMS_VSYNC_DISABLE 0x02
#define DPMS_SYNC_DISABLE_ALL 0x03
/*
* RAMDAC
@ -195,12 +196,12 @@
* cross the upper-left corner.
*/
#define ATR_CURSOR_ENABLE 0x0140
#define ATR_CURSOR_FG 0x0141 /* 3:3:2 */
#define ATR_CURSOR_BG 0x0142 /* 3:3:2 */
#define ATR_CURSOR_ADDRESS 0x0144 /* in KB from vram */
#define ATR_CURSOR_POSITION 0x0148
#define ATR_CURSOR_OFFSET 0x014c /* short access */
#define ATR_CURSOR_ENABLE 0x0140
#define ATR_CURSOR_FG 0x0141 /* 3:3:2 */
#define ATR_CURSOR_BG 0x0142 /* 3:3:2 */
#define ATR_CURSOR_ADDRESS 0x0144 /* in KB from vram */
#define ATR_CURSOR_POSITION 0x0148
#define ATR_CURSOR_HOTSPOT 0x014c /* short access */
/*
* Identification Register