#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/pciio.h>
#include <uvm/uvm_extern.h>
#include <machine/autoconf.h>
#include <machine/bus.h>
#include <machine/intr.h>
#include <machine/openfirm.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplayvar.h>
#include <dev/rasops/rasops.h>
#include <machine/fbvar.h>
#ifdef APERTURE
extern int allowaperture;
#endif
#define IFB_SHARED_SIGNATURE 0x00
#define SIG_IFB 0x09209911
#define SIG_JFB 0x05140213
#define IFB_SHARED_MONITOR_MODE 0x10
#define IFB_SHARED_WIDTH 0x14
#define IFB_SHARED_HEIGHT 0x18
#define IFB_SHARED_V_FREQ 0x1c
#define IFB_SHARED_TIMING_H_FP 0x20
#define IFB_SHARED_TIMING_H_SYNC 0x24
#define IFB_SHARED_TIMING_H_BP 0x28
#define IFB_SHARED_TIMING_V_FP 0x2c
#define IFB_SHARED_TIMING_V_SYNC 0x30
#define IFB_SHARED_TIMING_V_BP 0x34
#define IFB_SHARED_TIMING_FLAGS 0x38
#define IFB_SHARED_CMAP_DIRTY 0x3c
#define IFB_SHARED_TERM8_GSR 0x4c
#define IFB_SHARED_TERM8_SPR 0x50
#define IFB_SHARED_TERM8_SPLR 0x54
#define IFB_PCI_CFG 0x5c
#define IFB_PCI_CFG_BAR_OFFSET(x) ((x & 0x000000e0) >> 3)
#define JFB_REG_ENGINE 0x6000
#define IFB_REG_ENGINE 0x8000
#define IFB_REG_COMPONENT_SELECT 0x8040
#define IFB_REG_STATUS 0x8044
#define IFB_REG_STATUS_DONE 0x00000004
#define IFB_REG_MAGNIFY 0x8058
#define IFB_REG_MAGNIFY_DISABLE 0x00000000
#define IFB_REG_MAGNIFY_X2 0x00000040
#define IFB_REG_MAGNIFY_X4 0x00000080
#define IFB_REG_MAGNIFY_X8 0x000000c0
#define IFB_REG_MAGNIFY_WINDIV2 0x00000000
#define IFB_REG_MAGNIFY_WINDIV4 0x00000010
#define IFB_REG_MAGNIFY_WINDIV8 0x00000020
#define IFB_REG_MAGNIFY_WINDIV16 0x00000030
#define IFB_REG_RESOLUTION 0x8070
#define IFB_REG_CONFIG 0x8074
#define IFB_REG_FB32_0 0x8078
#define IFB_REG_FB32_1 0x807c
#define IFB_REG_FB8_0 0x8080
#define IFB_REG_FB8_1 0x8084
#define IFB_REG_FB_UNK0 0x8088
#define IFB_REG_FB_UNK1 0x808c
#define IFB_REG_FB_UNK2 0x8090
#define IFB_REG_CMAP_INDEX 0x80bc
#define IFB_REG_CMAP_DATA 0x80c0
#define IFB_REG_DPMS_STATE 0x80e4
#define IFB_REG_DPMS_OFF 0x00000000
#define IFB_REG_DPMS_SUSPEND 0x00000001
#define IFB_REG_DPMS_STANDBY 0x00000002
#define IFB_REG_DPMS_ON 0x00000003
#define IFB_ROP_CLEAR 0x00000000
#define IFB_ROP_SRC 0x00330000
#define IFB_ROP_XOR 0x00cc0000
#define IFB_ROP_SET 0x00ff0000
#define IFB_COORDS(x, y) ((x) | (y) << 16)
#define IFB_BLT_DIR_BACKWARDS_Y (0x08 | 0x02)
#define IFB_BLT_DIR_BACKWARDS_X (0x04 | 0x01)
#define IFB_PIXELMASK 0x7f
struct ifb_softc {
struct sunfb sc_sunfb;
bus_space_tag_t sc_mem_t;
pcitag_t sc_pcitag;
bus_space_handle_t sc_mem_h;
bus_addr_t sc_membase, sc_fb8bank0_base, sc_fb8bank1_base;
bus_size_t sc_memlen;
vaddr_t sc_memvaddr, sc_fb8bank0_vaddr, sc_fb8bank1_vaddr;
bus_space_handle_t sc_reg_h;
bus_addr_t sc_regbase;
bus_size_t sc_reglen;
volatile uint32_t *sc_comm;
u_int sc_acceltype;
#define IFB_ACCEL_NONE 0
#define IFB_ACCEL_IFB 1
#define IFB_ACCEL_JFB 2
void (*sc_rop)(void *, int, int, int, int, int, int, uint32_t, int32_t);
u_int sc_mode;
struct wsdisplay_emulops sc_old_ops;
u_int8_t sc_cmap_red[256];
u_int8_t sc_cmap_green[256];
u_int8_t sc_cmap_blue[256];
};
int ifb_ioctl(void *, u_long, caddr_t, int, struct proc *);
paddr_t ifb_mmap(void *, off_t, int);
void ifb_burner(void *, u_int, u_int);
struct wsdisplay_accessops ifb_accessops = {
.ioctl = ifb_ioctl,
.mmap = ifb_mmap,
.burn_screen = ifb_burner
};
int ifbmatch(struct device *, void *, void *);
void ifbattach(struct device *, struct device *, void *);
const struct cfattach ifb_ca = {
sizeof (struct ifb_softc), ifbmatch, ifbattach
};
struct cfdriver ifb_cd = {
NULL, "ifb", DV_DULL
};
int ifb_accel_identify(const char *);
static inline
u_int ifb_dac_value(u_int, u_int, u_int);
int ifb_getcmap(struct ifb_softc *, struct wsdisplay_cmap *);
static inline
int ifb_is_console(int);
int ifb_mapregs(struct ifb_softc *, struct pci_attach_args *);
int ifb_putcmap(struct ifb_softc *, struct wsdisplay_cmap *);
void ifb_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t);
void ifb_setcolormap(struct sunfb *,
void (*)(void *, u_int, u_int8_t, u_int8_t, u_int8_t));
void ifb_copyrect(struct ifb_softc *, int, int, int, int, int, int);
void ifb_fillrect(struct ifb_softc *, int, int, int, int, int);
static inline
void ifb_rop(struct ifb_softc *, int, int, int, int, int, int, uint32_t,
int32_t);
void ifb_rop_common(struct ifb_softc *, bus_addr_t, int, int, int, int,
int, int, uint32_t, int32_t);
void ifb_rop_ifb(void *, int, int, int, int, int, int, uint32_t, int32_t);
void ifb_rop_jfb(void *, int, int, int, int, int, int, uint32_t, int32_t);
int ifb_rop_wait(struct ifb_softc *);
int ifb_putchar_dumb(void *, int, int, u_int, uint32_t);
int ifb_copycols_dumb(void *, int, int, int, int);
int ifb_erasecols_dumb(void *, int, int, int, uint32_t);
int ifb_copyrows_dumb(void *, int, int, int);
int ifb_eraserows_dumb(void *, int, int, uint32_t);
int ifb_do_cursor_dumb(struct rasops_info *);
int ifb_copycols(void *, int, int, int, int);
int ifb_erasecols(void *, int, int, int, uint32_t);
int ifb_copyrows(void *, int, int, int);
int ifb_eraserows(void *, int, int, uint32_t);
int ifb_do_cursor(struct rasops_info *);
int
ifbmatch(struct device *parent, void *cf, void *aux)
{
return ifb_ident(aux);
}
void
ifbattach(struct device *parent, struct device *self, void *aux)
{
struct ifb_softc *sc = (struct ifb_softc *)self;
struct pci_attach_args *paa = aux;
struct rasops_info *ri;
uint32_t dev_comm;
int node, console;
char *name, *text;
char namebuf[32];
sc->sc_mem_t = paa->pa_memt;
sc->sc_pcitag = paa->pa_tag;
node = PCITAG_NODE(paa->pa_tag);
console = ifb_is_console(node);
printf("\n");
if (!node_has_property(node, "device_type")) {
printf("%s: secondary output not supported yet\n",
self->dv_xname);
return;
}
name = text = getpropstringA(node, "name", namebuf);
if (strncmp(text, "SUNW,", 5) == 0)
text += 5;
printf("%s: %s", self->dv_xname, text);
text = getpropstring(node, "model");
if (*text != '\0')
printf(" (%s)", text);
if (ifb_mapregs(sc, paa))
return;
sc->sc_fb8bank0_base = bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
IFB_REG_FB8_0);
sc->sc_fb8bank1_base = bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
IFB_REG_FB8_1);
sc->sc_memvaddr = (vaddr_t)bus_space_vaddr(sc->sc_mem_t, sc->sc_mem_h);
sc->sc_fb8bank0_vaddr = sc->sc_memvaddr +
sc->sc_fb8bank0_base - sc->sc_membase;
sc->sc_fb8bank1_vaddr = sc->sc_memvaddr +
sc->sc_fb8bank1_base - sc->sc_membase;
sc->sc_sunfb.sf_width = (bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
IFB_REG_RESOLUTION) & 0xffff) + 1;
sc->sc_sunfb.sf_height = (bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
IFB_REG_RESOLUTION) >> 16) + 1;
sc->sc_sunfb.sf_depth = 8;
sc->sc_sunfb.sf_linebytes = 1 << (bus_space_read_4(sc->sc_mem_t,
sc->sc_reg_h, IFB_REG_CONFIG) >> 16);
sc->sc_sunfb.sf_fbsize =
sc->sc_sunfb.sf_height * sc->sc_sunfb.sf_linebytes;
printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height);
ri = &sc->sc_sunfb.sf_ro;
ri->ri_bits = NULL;
ri->ri_hw = sc;
fbwscons_init(&sc->sc_sunfb, RI_BSWAP, console);
sc->sc_acceltype = ifb_accel_identify(name);
switch (sc->sc_acceltype) {
case IFB_ACCEL_IFB:
sc->sc_rop = ifb_rop_ifb;
break;
case IFB_ACCEL_JFB:
if (OF_getprop(node, "dev-comm", &dev_comm,
sizeof dev_comm) != -1) {
sc->sc_comm = (volatile uint32_t *)(vaddr_t)dev_comm;
}
sc->sc_rop = ifb_rop_jfb;
break;
}
if (sc->sc_acceltype != IFB_ACCEL_NONE) {
ifb_rop(sc, 0, 0, 0, 0, sc->sc_sunfb.sf_width,
sc->sc_sunfb.sf_height, IFB_ROP_CLEAR,
console ? ~IFB_PIXELMASK : ~0);
if (ifb_rop_wait(sc) == 0) {
sc->sc_acceltype = IFB_ACCEL_NONE;
}
}
if (sc->sc_acceltype == IFB_ACCEL_NONE) {
ri->ri_flg &= ~RI_FULLCLEAR;
if (!console) {
bzero((void *)sc->sc_fb8bank0_vaddr,
sc->sc_sunfb.sf_fbsize);
bzero((void *)sc->sc_fb8bank1_vaddr,
sc->sc_sunfb.sf_fbsize);
}
}
sc->sc_fb8bank0_vaddr += ri->ri_bits - ri->ri_origbits;
sc->sc_fb8bank1_vaddr += ri->ri_bits - ri->ri_origbits;
sc->sc_old_ops = ri->ri_ops;
if (sc->sc_acceltype != IFB_ACCEL_NONE) {
ri->ri_ops.copyrows = ifb_copyrows;
ri->ri_ops.copycols = ifb_copycols;
ri->ri_ops.eraserows = ifb_eraserows;
ri->ri_ops.erasecols = ifb_erasecols;
ri->ri_ops.putchar = ifb_putchar_dumb;
ri->ri_do_cursor = ifb_do_cursor;
} else {
ri->ri_ops.copyrows = ifb_copyrows_dumb;
ri->ri_ops.copycols = ifb_copycols_dumb;
ri->ri_ops.eraserows = ifb_eraserows_dumb;
ri->ri_ops.erasecols = ifb_erasecols_dumb;
ri->ri_ops.putchar = ifb_putchar_dumb;
ri->ri_do_cursor = ifb_do_cursor_dumb;
}
ifb_setcolormap(&sc->sc_sunfb, ifb_setcolor);
sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
if (console)
fbwscons_console_init(&sc->sc_sunfb, -1);
fbwscons_attach(&sc->sc_sunfb, &ifb_accessops, console);
}
int
ifb_accel_identify(const char *name)
{
if (strcmp(name, "SUNW,Expert3D") == 0 ||
strcmp(name, "SUNW,Expert3D-Lite") == 0)
return IFB_ACCEL_IFB;
if (strcmp(name, "SUNW,XVR-1200") == 0)
return IFB_ACCEL_JFB;
if (strcmp(name, "SUNW,XVR-600") == 0)
return IFB_ACCEL_JFB;
return IFB_ACCEL_NONE;
}
int
ifb_ioctl(void *v, u_long cmd, caddr_t data, int flags, struct proc *p)
{
struct ifb_softc *sc = v;
struct wsdisplay_fbinfo *wdf;
struct pcisel *sel;
int mode;
switch (cmd) {
case WSDISPLAYIO_GTYPE:
*(u_int *)data = WSDISPLAY_TYPE_IFB;
break;
case WSDISPLAYIO_SMODE:
mode = *(u_int *)data;
if (mode == WSDISPLAYIO_MODE_EMUL)
ifb_setcolormap(&sc->sc_sunfb, ifb_setcolor);
sc->sc_mode = mode;
break;
case WSDISPLAYIO_GINFO:
wdf = (void *)data;
wdf->height = sc->sc_sunfb.sf_height;
wdf->width = sc->sc_sunfb.sf_width;
wdf->depth = sc->sc_sunfb.sf_depth;
wdf->stride = sc->sc_sunfb.sf_linebytes;
wdf->offset = 0;
wdf->cmsize = 256;
break;
case WSDISPLAYIO_LINEBYTES:
*(u_int *)data = sc->sc_sunfb.sf_linebytes;
break;
case WSDISPLAYIO_GETCMAP:
return ifb_getcmap(sc, (struct wsdisplay_cmap *)data);
case WSDISPLAYIO_PUTCMAP:
return ifb_putcmap(sc, (struct wsdisplay_cmap *)data);
case WSDISPLAYIO_GPCIID:
sel = (struct pcisel *)data;
sel->pc_bus = PCITAG_BUS(sc->sc_pcitag);
sel->pc_dev = PCITAG_DEV(sc->sc_pcitag);
sel->pc_func = PCITAG_FUN(sc->sc_pcitag);
break;
case WSDISPLAYIO_SVIDEO:
case WSDISPLAYIO_GVIDEO:
break;
case WSDISPLAYIO_GCURPOS:
case WSDISPLAYIO_SCURPOS:
case WSDISPLAYIO_GCURMAX:
case WSDISPLAYIO_GCURSOR:
case WSDISPLAYIO_SCURSOR:
default:
return -1;
}
return 0;
}
static inline
u_int
ifb_dac_value(u_int r, u_int g, u_int b)
{
r = (r << 2) | (r >> 6);
g = (g << 2) | (g >> 6);
b = (b << 2) | (b >> 6);
return (b << 20) | (g << 10) | r;
}
int
ifb_getcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm)
{
u_int index = cm->index;
u_int count = cm->count;
int error;
if (index >= 256 || count > 256 - index)
return EINVAL;
error = copyout(&sc->sc_cmap_red[index], cm->red, count);
if (error)
return error;
error = copyout(&sc->sc_cmap_green[index], cm->green, count);
if (error)
return error;
error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
if (error)
return error;
return 0;
}
int
ifb_putcmap(struct ifb_softc *sc, struct wsdisplay_cmap *cm)
{
u_int index = cm->index;
u_int count = cm->count;
u_int i;
int error;
u_char *r, *g, *b;
if (index >= 256 || count > 256 - index)
return EINVAL;
if ((error = copyin(cm->red, &sc->sc_cmap_red[index], count)) != 0)
return error;
if ((error = copyin(cm->green, &sc->sc_cmap_green[index], count)) != 0)
return error;
if ((error = copyin(cm->blue, &sc->sc_cmap_blue[index], count)) != 0)
return error;
r = &sc->sc_cmap_red[index];
g = &sc->sc_cmap_green[index];
b = &sc->sc_cmap_blue[index];
for (i = 0; i < count; i++) {
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h,
IFB_REG_CMAP_INDEX, index);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, IFB_REG_CMAP_DATA,
ifb_dac_value(*r, *g, *b));
r++, g++, b++, index++;
}
return 0;
}
void
ifb_setcolor(void *v, u_int index, u_int8_t r, u_int8_t g, u_int8_t b)
{
struct ifb_softc *sc = v;
sc->sc_cmap_red[index] = r;
sc->sc_cmap_green[index] = g;
sc->sc_cmap_blue[index] = b;
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, IFB_REG_CMAP_INDEX,
index);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, IFB_REG_CMAP_DATA,
ifb_dac_value(r, g, b));
}
void
ifb_setcolormap(struct sunfb *sf,
void (*setcolor)(void *, u_int, u_int8_t, u_int8_t, u_int8_t))
{
struct rasops_info *ri = &sf->sf_ro;
int i;
const u_char *color;
for (i = 0x00; i < 0x10; i++) {
color = &rasops_cmap[i * 3];
setcolor(sf, i, color[0], color[1], color[2]);
}
for (i = 0x70; i < 0x80; i++) {
color = &rasops_cmap[(0xf0 | i) * 3];
setcolor(sf, i, color[0], color[1], color[2]);
}
ri->ri_devcmap[WSCOL_WHITE] = 0x00000000;
ri->ri_devcmap[WSCOL_BLACK] = 0x01010101;
ri->ri_devcmap[WSCOL_RED] = 0x07070707;
color = &rasops_cmap[(WSCOL_WHITE + 8) * 3];
setcolor(sf, 0, color[0], color[1], color[2]);
setcolor(sf, IFB_PIXELMASK ^ 0, ~color[0], ~color[1], ~color[2]);
color = &rasops_cmap[WSCOL_BLACK * 3];
setcolor(sf, 1, color[0], color[1], color[2]);
setcolor(sf, IFB_PIXELMASK ^ 1, ~color[0], ~color[1], ~color[2]);
color = &rasops_cmap[WSCOL_RED * 3];
setcolor(sf, 7, color[0], color[1], color[2]);
setcolor(sf, IFB_PIXELMASK ^ 7, ~color[0], ~color[1], ~color[2]);
}
paddr_t
ifb_mmap(void *v, off_t off, int prot)
{
struct ifb_softc *sc = (struct ifb_softc *)v;
switch (sc->sc_mode) {
case WSDISPLAYIO_MODE_MAPPED:
off -= 0x00000000;
if (off >= 0 && off < round_page(sc->sc_sunfb.sf_fbsize)) {
return bus_space_mmap(sc->sc_mem_t,
sc->sc_fb8bank0_base,
off, prot, BUS_SPACE_MAP_LINEAR);
}
off -= 0x01000000;
if (off >= 0 && off < round_page(sc->sc_sunfb.sf_fbsize)) {
return bus_space_mmap(sc->sc_mem_t,
sc->sc_fb8bank1_base,
off, prot, BUS_SPACE_MAP_LINEAR);
}
#ifdef APERTURE
off -= 0x01000000;
if (allowaperture != 0 && sc->sc_acceltype != IFB_ACCEL_NONE) {
if (off >= 0 && off < round_page(sc->sc_reglen)) {
return bus_space_mmap(sc->sc_mem_t,
sc->sc_regbase,
off, prot, BUS_SPACE_MAP_LINEAR);
}
}
#endif
break;
}
return -1;
}
void
ifb_burner(void *v, u_int on, u_int flags)
{
struct ifb_softc *sc = (struct ifb_softc *)v;
int s;
uint32_t dpms;
s = splhigh();
if (on)
dpms = IFB_REG_DPMS_ON;
else {
#ifdef notyet
if (flags & WSDISPLAY_BURN_VBLANK)
dpms = IFB_REG_DPMS_SUSPEND;
else
#endif
dpms = IFB_REG_DPMS_STANDBY;
}
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, IFB_REG_DPMS_STATE, dpms);
splx(s);
}
static inline int
ifb_is_console(int node)
{
extern int fbnode;
return fbnode == node;
}
int
ifb_mapregs(struct ifb_softc *sc, struct pci_attach_args *pa)
{
u_int32_t cf;
int bar, rc;
cf = pci_conf_read(pa->pa_pc, pa->pa_tag, IFB_PCI_CFG);
bar = PCI_MAPREG_START + IFB_PCI_CFG_BAR_OFFSET(cf);
cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar);
if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO)
rc = EINVAL;
else {
rc = pci_mapreg_map(pa, bar, cf,
BUS_SPACE_MAP_LINEAR, NULL, &sc->sc_mem_h,
&sc->sc_membase, &sc->sc_memlen, 0);
}
if (rc != 0) {
printf("\n%s: can't map video memory\n",
sc->sc_sunfb.sf_dev.dv_xname);
return rc;
}
cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar + 4);
if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO)
rc = EINVAL;
else {
rc = pci_mapreg_map(pa, bar + 4, cf,
0, NULL, &sc->sc_reg_h,
&sc->sc_regbase, &sc->sc_reglen, 0x9000);
}
if (rc != 0) {
printf("\n%s: can't map register space\n",
sc->sc_sunfb.sf_dev.dv_xname);
return rc;
}
return 0;
}
int
ifb_putchar_dumb(void *cookie, int row, int col, u_int uc, uint32_t attr)
{
struct rasops_info *ri = cookie;
struct ifb_softc *sc = ri->ri_hw;
ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
sc->sc_old_ops.putchar(cookie, row, col, uc, attr);
ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
sc->sc_old_ops.putchar(cookie, row, col, uc, attr);
return 0;
}
int
ifb_copycols_dumb(void *cookie, int row, int src, int dst, int num)
{
struct rasops_info *ri = cookie;
struct ifb_softc *sc = ri->ri_hw;
ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
sc->sc_old_ops.copycols(cookie, row, src, dst, num);
ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
sc->sc_old_ops.copycols(cookie, row, src, dst, num);
return 0;
}
int
ifb_erasecols_dumb(void *cookie, int row, int col, int num, uint32_t attr)
{
struct rasops_info *ri = cookie;
struct ifb_softc *sc = ri->ri_hw;
ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
sc->sc_old_ops.erasecols(cookie, row, col, num, attr);
ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
sc->sc_old_ops.erasecols(cookie, row, col, num, attr);
return 0;
}
int
ifb_copyrows_dumb(void *cookie, int src, int dst, int num)
{
struct rasops_info *ri = cookie;
struct ifb_softc *sc = ri->ri_hw;
ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
sc->sc_old_ops.copyrows(cookie, src, dst, num);
ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
sc->sc_old_ops.copyrows(cookie, src, dst, num);
return 0;
}
int
ifb_eraserows_dumb(void *cookie, int row, int num, uint32_t attr)
{
struct rasops_info *ri = cookie;
struct ifb_softc *sc = ri->ri_hw;
ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
sc->sc_old_ops.eraserows(cookie, row, num, attr);
ri->ri_bits = (void *)sc->sc_fb8bank1_vaddr;
sc->sc_old_ops.eraserows(cookie, row, num, attr);
return 0;
}
#define CURSOR_MASK 0x7f7f7f7f
int
ifb_do_cursor_dumb(struct rasops_info *ri)
{
struct ifb_softc *sc = ri->ri_hw;
int full1, height, cnt, slop1, slop2, row, col;
int ovl_offset = sc->sc_fb8bank1_vaddr - sc->sc_fb8bank0_vaddr;
u_char *dp0, *dp1, *rp;
row = ri->ri_crow;
col = ri->ri_ccol;
ri->ri_bits = (void *)sc->sc_fb8bank0_vaddr;
rp = ri->ri_bits + row * ri->ri_yscale + col * ri->ri_xscale;
height = ri->ri_font->fontheight;
slop1 = (4 - ((long)rp & 3)) & 3;
if (slop1 > ri->ri_xscale)
slop1 = ri->ri_xscale;
slop2 = (ri->ri_xscale - slop1) & 3;
full1 = (ri->ri_xscale - slop1 - slop2) >> 2;
if ((slop1 | slop2) == 0) {
while (height--) {
dp0 = rp;
dp1 = dp0 + ovl_offset;
rp += ri->ri_stride;
for (cnt = full1; cnt; cnt--) {
*(int32_t *)dp0 ^= CURSOR_MASK;
*(int32_t *)dp1 ^= CURSOR_MASK;
dp0 += 4;
dp1 += 4;
}
}
} else {
while (height--) {
dp0 = rp;
dp1 = dp0 + ovl_offset;
rp += ri->ri_stride;
if (slop1 & 1) {
*dp0++ ^= (u_char)CURSOR_MASK;
*dp1++ ^= (u_char)CURSOR_MASK;
}
if (slop1 & 2) {
*(int16_t *)dp0 ^= (int16_t)CURSOR_MASK;
*(int16_t *)dp1 ^= (int16_t)CURSOR_MASK;
dp0 += 2;
dp1 += 2;
}
for (cnt = full1; cnt; cnt--) {
*(int32_t *)dp0 ^= CURSOR_MASK;
*(int32_t *)dp1 ^= CURSOR_MASK;
dp0 += 4;
dp1 += 4;
}
if (slop2 & 1) {
*dp0++ ^= (u_char)CURSOR_MASK;
*dp1++ ^= (u_char)CURSOR_MASK;
}
if (slop2 & 2) {
*(int16_t *)dp0 ^= (int16_t)CURSOR_MASK;
*(int16_t *)dp1 ^= (int16_t)CURSOR_MASK;
}
}
}
return 0;
}
int
ifb_copycols(void *cookie, int row, int src, int dst, int num)
{
struct rasops_info *ri = cookie;
struct ifb_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;
ifb_copyrect(sc, ri->ri_xorigin + src, ri->ri_yorigin + row,
ri->ri_xorigin + dst, ri->ri_yorigin + row,
num, ri->ri_font->fontheight);
return 0;
}
int
ifb_erasecols(void *cookie, int row, int col, int num, uint32_t attr)
{
struct rasops_info *ri = cookie;
struct ifb_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;
ifb_fillrect(sc, ri->ri_xorigin + col, ri->ri_yorigin + row,
num, ri->ri_font->fontheight, ri->ri_devcmap[bg]);
return 0;
}
int
ifb_copyrows(void *cookie, int src, int dst, int num)
{
struct rasops_info *ri = cookie;
struct ifb_softc *sc = ri->ri_hw;
num *= ri->ri_font->fontheight;
src *= ri->ri_font->fontheight;
dst *= ri->ri_font->fontheight;
ifb_copyrect(sc, ri->ri_xorigin, ri->ri_yorigin + src,
ri->ri_xorigin, ri->ri_yorigin + dst, ri->ri_emuwidth, num);
return 0;
}
int
ifb_eraserows(void *cookie, int row, int num, uint32_t attr)
{
struct rasops_info *ri = cookie;
struct ifb_softc *sc = ri->ri_hw;
int bg, fg;
int x, y, w;
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;
}
ifb_fillrect(sc, x, y, w, num, ri->ri_devcmap[bg]);
return 0;
}
void
ifb_copyrect(struct ifb_softc *sc, int sx, int sy, int dx, int dy, int w, int h)
{
ifb_rop(sc, sx, sy, dx, dy, w, h, IFB_ROP_SRC, IFB_PIXELMASK);
ifb_rop_wait(sc);
}
void
ifb_fillrect(struct ifb_softc *sc, int x, int y, int w, int h, int bg)
{
int32_t mask;
mask = IFB_PIXELMASK & bg;
if (mask != 0) {
ifb_rop(sc, x, y, x, y, w, h, IFB_ROP_SET, mask);
ifb_rop_wait(sc);
}
mask = IFB_PIXELMASK & ~bg;
if (mask != 0) {
ifb_rop(sc, x, y, x, y, w, h, IFB_ROP_CLEAR, mask);
ifb_rop_wait(sc);
}
}
static inline void
ifb_rop(struct ifb_softc *sc, int sx, int sy, int dx, int dy, int w, int h,
uint32_t rop, int32_t planemask)
{
(*sc->sc_rop)(sc, sx, sy, dx, dy, w, h, rop, planemask);
}
void
ifb_rop_common(struct ifb_softc *sc, bus_addr_t reg, int sx, int sy,
int dx, int dy, int w, int h, uint32_t rop, int32_t planemask)
{
int dir = 0;
if (sy < dy ) {
sy += h - 1;
dy += h;
dir |= IFB_BLT_DIR_BACKWARDS_Y;
}
if (sx < dx ) {
sx += w - 1;
dx += w;
dir |= IFB_BLT_DIR_BACKWARDS_X;
}
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 0x61000001);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 0);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 0x6301c080);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 0x80000000);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, rop);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, planemask);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 0);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 0x64000303);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, IFB_COORDS(0, 0));
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 0);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 0x00030000);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 0x2200010d);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 0x33f01000 | dir);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, IFB_COORDS(dx, dy));
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, IFB_COORDS(w, h));
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, IFB_COORDS(sx, sy));
}
void
ifb_rop_ifb(void *v, int sx, int sy, int dx, int dy, int w, int h,
uint32_t rop, int32_t planemask)
{
struct ifb_softc *sc = (struct ifb_softc *)v;
bus_addr_t reg = IFB_REG_ENGINE;
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 2);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 1);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 0x540101ff);
ifb_rop_common(sc, reg, sx, sy, dx, dy, w, h, rop, planemask);
}
void
ifb_rop_jfb(void *v, int sx, int sy, int dx, int dy, int w, int h,
uint32_t rop, int32_t planemask)
{
struct ifb_softc *sc = (struct ifb_softc *)v;
bus_addr_t reg = JFB_REG_ENGINE;
uint32_t spr, splr;
if (sc->sc_comm != NULL) {
spr = sc->sc_comm[IFB_SHARED_TERM8_SPR >> 2];
splr = sc->sc_comm[IFB_SHARED_TERM8_SPLR >> 2];
} else {
spr = 0x54ff0303;
splr = 0x5c0000ff;
}
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 0x00400016);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 0x5b000002);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 0x5a000000);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, spr);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, splr);
ifb_rop_common(sc, reg, sx, sy, dx, dy, w, h, rop, planemask);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 0x5a000001);
bus_space_write_4(sc->sc_mem_t, sc->sc_reg_h, reg, 0x5b000001);
}
int
ifb_rop_wait(struct ifb_softc *sc)
{
int i;
for (i = 1000000; i != 0; i--) {
if (bus_space_read_4(sc->sc_mem_t, sc->sc_reg_h,
IFB_REG_STATUS) & IFB_REG_STATUS_DONE)
break;
DELAY(1);
}
return i;
}
int
ifb_do_cursor(struct rasops_info *ri)
{
struct ifb_softc *sc = ri->ri_hw;
int y, x;
y = ri->ri_yorigin + ri->ri_crow * ri->ri_font->fontheight;
x = ri->ri_xorigin + ri->ri_ccol * ri->ri_font->fontwidth;
ifb_rop(sc, x, y, x, y, ri->ri_font->fontwidth, ri->ri_font->fontheight,
IFB_ROP_XOR, IFB_PIXELMASK);
ifb_rop_wait(sc);
return 0;
}