implement WSDISPLAYIO_{GET|PUT}CMAP ioctl()s

while there:
- unmap registers and vram only in WSDISPLAYIO_MODE_MAPPED ( so DRM can map
  them ) but not in WSDISPLAYIO_MODE_DUMBFB ( so wsfb can do things that
  require hardware access, like palette and cursor ioctl()s )
- reject ioctl()s that need hardware access if registers are unmapped ( so we
  don't crash instead )
- use the same bit order in cursor sprite images as the other drivers do
with all this, Xorg with wsfb works properly on top of radeonfb

tested on i386 and macppc ( fingers crossed for alpha ;) )
This commit is contained in:
macallan 2014-01-22 07:57:33 +00:00
parent 708b399e9d
commit 4f788ce7bc
2 changed files with 166 additions and 69 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: radeonfb.c,v 1.81 2014/01/14 09:46:42 macallan Exp $ */
/* $NetBSD: radeonfb.c,v 1.82 2014/01/22 07:57:33 macallan Exp $ */
/*-
* Copyright (c) 2006 Itronix Inc.
@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: radeonfb.c,v 1.81 2014/01/14 09:46:42 macallan Exp $");
__KERNEL_RCSID(0, "$NetBSD: radeonfb.c,v 1.82 2014/01/22 07:57:33 macallan Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -140,6 +140,9 @@ static int radeonfb_set_cursor(struct radeonfb_display *,
struct wsdisplay_cursor *);
static int radeonfb_set_curpos(struct radeonfb_display *,
struct wsdisplay_curpos *);
static void radeonfb_putpal(struct radeonfb_display *, int, int, int, int);
static int radeonfb_putcmap(struct radeonfb_display *, struct wsdisplay_cmap *);
static int radeonfb_getcmap(struct radeonfb_display *, struct wsdisplay_cmap *);
/* acceleration support */
static void radeonfb_rectfill(struct radeonfb_display *, int dstx, int dsty,
@ -1075,6 +1078,21 @@ radeonfb_ioctl(void *v, void *vs,
dp = (struct radeonfb_display *)vd->cookie;
sc = dp->rd_softc;
/* can't do these without registers being mapped */
if (!sc->sc_mapped) {
switch (cmd) {
case WSDISPLAYIO_GVIDEO:
case WSDISPLAYIO_SVIDEO:
case WSDISPLAYIO_GETCMAP:
case WSDISPLAYIO_PUTCMAP:
case WSDISPLAYIO_SCURSOR:
case WSDISPLAYIO_GCURPOS:
case WSDISPLAYIO_SCURPOS:
case WSDISPLAYIO_SETPARAM:
return EINVAL;
}
}
switch (cmd) {
case WSDISPLAYIO_GTYPE:
*(unsigned *)d = WSDISPLAY_TYPE_PCIMISC;
@ -1104,19 +1122,15 @@ radeonfb_ioctl(void *v, void *vs,
return 0;
case WSDISPLAYIO_GETCMAP:
#if 0
if (dp->rd_bpp == 8)
return radeonfb_getcmap(sc,
return radeonfb_getcmap(dp,
(struct wsdisplay_cmap *)d);
#endif
return EINVAL;
case WSDISPLAYIO_PUTCMAP:
#if 0
if (dp->rd_bpp == 8)
return radeonfb_putcmap(sc,
return radeonfb_putcmap(dp,
(struct wsdisplay_cmap *)d);
#endif
return EINVAL;
case WSDISPLAYIO_LINEBYTES:
@ -1126,9 +1140,12 @@ radeonfb_ioctl(void *v, void *vs,
case WSDISPLAYIO_SMODE:
if (*(int *)d != dp->rd_wsmode) {
dp->rd_wsmode = *(int *)d;
if ((dp->rd_wsmode == WSDISPLAYIO_MODE_EMUL) ||
(dp->rd_wsmode == WSDISPLAYIO_MODE_DUMBFB))
radeonfb_map(sc);
if ((dp->rd_wsmode == WSDISPLAYIO_MODE_EMUL) &&
(dp->rd_vd.active)) {
radeonfb_map(sc);
radeonfb_engine_init(dp);
glyphcache_wipe(&dp->rd_gc);
radeonfb_init_palette(dp);
@ -1136,9 +1153,9 @@ radeonfb_ioctl(void *v, void *vs,
radeonfb_rectfill(dp, 0, 0, dp->rd_virtx,
dp->rd_virty, dp->rd_bg);
vcons_redraw_screen(dp->rd_vd.active);
} else {
radeonfb_unmap(sc);
}
if (dp->rd_wsmode == WSDISPLAYIO_MODE_MAPPED)
radeonfb_unmap(sc);
}
return 0;
@ -2549,20 +2566,12 @@ radeonfb_init_misc(struct radeonfb_softc *sc)
PUT32(sc, RADEON_GEN_INT_STATUS, GET32(sc, RADEON_GEN_INT_STATUS));
}
/*
* This loads a linear color map for true color.
*/
void
radeonfb_init_palette(struct radeonfb_display *dp)
static void
radeonfb_putpal(struct radeonfb_display *dp, int idx, int r, int g, int b)
{
struct radeonfb_softc *sc = dp->rd_softc;
int i, cc;
int crtc, cc;
uint32_t vclk;
int crtc;
#define DAC_WIDTH ((1 << 10) - 1)
#define CLUT_WIDTH ((1 << 8) - 1)
#define CLUT_COLOR(i) ((i * DAC_WIDTH * 2 / CLUT_WIDTH + 1) / 2)
vclk = GETPLL(sc, RADEON_VCLK_ECP_CNTL);
PUTPLL(sc, RADEON_VCLK_ECP_CNTL, vclk & ~RADEON_PIXCLK_DAC_ALWAYS_ONb);
@ -2577,55 +2586,124 @@ radeonfb_init_palette(struct radeonfb_display *dp)
else
CLR32(sc, RADEON_DAC_CNTL2, RADEON_DAC2_PALETTE_ACC_CTL);
PUT32(sc, RADEON_PALETTE_INDEX, 0);
if (dp->rd_bpp == 8) {
/* R3G3B2 palette */
int j = 0;
uint32_t tmp, r, g, b;
for (i = 0; i <= CLUT_WIDTH; ++i) {
tmp = i & 0xe0;
/*
* replicate bits so 0xe0 maps to a red value of 0xff
* in order to make white look actually white
*/
tmp |= (tmp >> 3) | (tmp >> 6);
r = tmp;
tmp = (i & 0x1c) << 3;
tmp |= (tmp >> 3) | (tmp >> 6);
g = tmp;
tmp = (i & 0x03) << 6;
tmp |= tmp >> 2;
tmp |= tmp >> 4;
b = tmp;
PUT32(sc, RADEON_PALETTE_30_DATA,
(r << 22) |
(g << 12) |
(b << 2));
j += 3;
}
} else {
/* linear ramp */
for (i = 0; i <= CLUT_WIDTH; ++i) {
PUT32(sc, RADEON_PALETTE_30_DATA,
(CLUT_COLOR(i) << 10) |
(CLUT_COLOR(i) << 20) |
(CLUT_COLOR(i)));
}
}
PUT32(sc, RADEON_PALETTE_INDEX, idx);
PUT32(sc, RADEON_PALETTE_30_DATA,
(r << 22) | (g << 12) | (b << 2));
}
CLR32(sc, RADEON_DAC_CNTL2, RADEON_DAC2_PALETTE_ACC_CTL);
PRINTREG(RADEON_DAC_CNTL2);
PUTPLL(sc, RADEON_VCLK_ECP_CNTL, vclk);
}
/*
* This loads a linear color map for true color.
*/
void
radeonfb_init_palette(struct radeonfb_display *dp)
{
int i;
#define DAC_WIDTH ((1 << 10) - 1)
#define CLUT_WIDTH ((1 << 8) - 1)
#define CLUT_COLOR(i) ((i * DAC_WIDTH * 2 / CLUT_WIDTH + 1) / 2)
if (dp->rd_bpp == 8) {
/* R3G3B2 palette */
uint32_t tmp, r, g, b;
for (i = 0; i <= CLUT_WIDTH; ++i) {
tmp = i & 0xe0;
/*
* replicate bits so 0xe0 maps to a red value of 0xff
* in order to make white look actually white
*/
tmp |= (tmp >> 3) | (tmp >> 6);
r = tmp;
tmp = (i & 0x1c) << 3;
tmp |= (tmp >> 3) | (tmp >> 6);
g = tmp;
tmp = (i & 0x03) << 6;
tmp |= tmp >> 2;
tmp |= tmp >> 4;
b = tmp;
radeonfb_putpal(dp, i, r, g, b);
}
} else {
/* linear ramp */
for (i = 0; i <= CLUT_WIDTH; ++i) {
radeonfb_putpal(dp, i, i, i, i);
}
}
}
static int
radeonfb_putcmap(struct radeonfb_display *dp, struct wsdisplay_cmap *cm)
{
u_char *r, *g, *b;
u_int index = cm->index;
u_int count = cm->count;
int i, error;
u_char rbuf[256], gbuf[256], bbuf[256];
#ifdef GENFB_DEBUG
aprint_debug("putcmap: %d %d\n",index, count);
#endif
if (cm->index >= 256 || cm->count > 256 ||
(cm->index + cm->count) > 256)
return EINVAL;
error = copyin(cm->red, &rbuf[index], count);
if (error)
return error;
error = copyin(cm->green, &gbuf[index], count);
if (error)
return error;
error = copyin(cm->blue, &bbuf[index], count);
if (error)
return error;
memcpy(&dp->rd_cmap_red[index], &rbuf[index], count);
memcpy(&dp->rd_cmap_green[index], &gbuf[index], count);
memcpy(&dp->rd_cmap_blue[index], &bbuf[index], count);
r = &dp->rd_cmap_red[index];
g = &dp->rd_cmap_green[index];
b = &dp->rd_cmap_blue[index];
for (i = 0; i < count; i++) {
radeonfb_putpal(dp, index, *r, *g, *b);
index++;
r++, g++, b++;
}
return 0;
}
static int
radeonfb_getcmap(struct radeonfb_display *dp, struct wsdisplay_cmap *cm)
{
u_int index = cm->index;
u_int count = cm->count;
int error;
if (index >= 255 || count > 256 || index + count > 256)
return EINVAL;
error = copyout(&dp->rd_cmap_red[index], cm->red, count);
if (error)
return error;
error = copyout(&dp->rd_cmap_green[index], cm->green, count);
if (error)
return error;
error = copyout(&dp->rd_cmap_blue[index], cm->blue, count);
if (error)
return error;
return 0;
}
/*
* Bugs in some R300 hardware requires this when accessing CLOCK_CNTL_INDEX.
*/
@ -3498,6 +3576,22 @@ radeonfb_set_cursor(struct radeonfb_display *dp, struct wsdisplay_cursor *wc)
return 0;
}
static uint8_t
radeonfb_backwards(uint8_t d)
{
uint8_t l;
l = d << 7;
l |= ((d & 0x02) << 5);
l |= ((d & 0x04) << 3);
l |= ((d & 0x08) << 1);
l |= ((d & 0x10) >> 1);
l |= ((d & 0x20) >> 3);
l |= ((d & 0x40) >> 5);
l |= ((d & 0x80) >> 7);
return l;
}
/*
* Change the cursor shape. Call this with the cursor locked to avoid
* flickering/tearing.
@ -3563,6 +3657,11 @@ radeonfb_cursor_shape(struct radeonfb_display *dp)
}
}
for (i = 0; i < 512; i++) {
and[i] = radeonfb_backwards(and[i]);
xor[i] = radeonfb_backwards(xor[i]);
}
/* copy the image into place */
for (i = 0; i < 64; i++) {
memcpy((uint8_t *)dp->rd_curptr + (i * 16),

View File

@ -1,4 +1,4 @@
/* $NetBSD: radeonfbvar.h,v 1.18 2013/03/28 17:25:10 macallan Exp $ */
/* $NetBSD: radeonfbvar.h,v 1.19 2014/01/22 07:57:33 macallan Exp $ */
/*-
* Copyright (c) 2006 Itronix Inc.
@ -196,11 +196,9 @@ struct radeonfb_display {
void (*rd_putchar)(void *, int, int, u_int, long);
glyphcache rd_gc;
#if 0
uint8_t rd_cmap_red[256];
uint8_t rd_cmap_green[256];
uint8_t rd_cmap_blue[256];
#endif
#ifdef SPLASHSCREEN
struct splash_info rd_splash;