Add a basic driver for the SIS315 Pro frame buffer found on some loogson2-based
systems, from OpenBSD. At this time it can only map the framebuffer and attaches wscons, using whatever resolution was configured by the firmware. It doens't support any accelaration or mode change.
This commit is contained in:
parent
4c44c335c5
commit
fe2e97b4b5
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: files.pci,v 1.346 2011/08/24 20:27:35 dyoung Exp $
|
||||
# $NetBSD: files.pci,v 1.347 2011/08/27 13:28:37 bouyer Exp $
|
||||
#
|
||||
# Config file and device description for machine-independent PCI code.
|
||||
# Included by ports that need it. Requires that the SCSI files be
|
||||
|
@ -1080,3 +1080,7 @@ device pwdog: sysmon_envsys
|
|||
attach pwdog at pci
|
||||
file dev/pci/pwdog.c pwdog
|
||||
|
||||
# SIS 315 Pro frame buffer
|
||||
device sisfb: wsemuldisplaydev, rasops8, rasops15, rasops16, rasops32, vcons
|
||||
attach sisfb at pci
|
||||
file dev/pci/sisfb.c sisfb needs-flag
|
||||
|
|
|
@ -0,0 +1,755 @@
|
|||
/* $OpenBSD: sisfb.c,v 1.2 2010/12/26 15:40:59 miod Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Miodrag Vallat.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Minimalistic driver for the SIS315 Pro frame buffer found on the
|
||||
* Lemote Fuloong 2F systems.
|
||||
* Does not support accelaration, mode change, secondary output, or
|
||||
* anything fancy.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: sisfb.c,v 1.1 2011/08/27 13:28:37 bouyer Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <uvm/uvm_extern.h>
|
||||
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
#include <dev/pci/pcidevs.h>
|
||||
#include <dev/pci/pciio.h>
|
||||
|
||||
#include <dev/videomode/videomode.h>
|
||||
|
||||
#include <dev/wscons/wsdisplayvar.h>
|
||||
#include <dev/wscons/wsconsio.h>
|
||||
#include <dev/wsfont/wsfont.h>
|
||||
#include <dev/rasops/rasops.h>
|
||||
#include <dev/wscons/wsdisplay_vconsvar.h>
|
||||
#include <dev/pci/wsdisplay_pci.h>
|
||||
|
||||
#include <dev/i2c/i2cvar.h>
|
||||
|
||||
#include <dev/pci/sisfb.h>
|
||||
|
||||
struct sisfb_softc;
|
||||
|
||||
/* minimal frame buffer information, suitable for early console */
|
||||
|
||||
struct sisfb {
|
||||
struct sisfb_softc *sc;
|
||||
uint8_t cmap[256 * 3];
|
||||
|
||||
bus_space_tag_t fbt;
|
||||
bus_space_handle_t fbh;
|
||||
|
||||
bus_space_tag_t mmiot;
|
||||
bus_space_handle_t mmioh;
|
||||
|
||||
bus_space_tag_t iot;
|
||||
bus_space_handle_t ioh;
|
||||
|
||||
struct vcons_screen vcs;
|
||||
struct wsscreen_descr wsd;
|
||||
|
||||
int fb_depth;
|
||||
int fb_width;
|
||||
int fb_height;
|
||||
int fb_stride;
|
||||
void *fb_addr;
|
||||
};
|
||||
|
||||
struct sisfb_softc {
|
||||
device_t sc_dev;
|
||||
struct sisfb *sc_fb;
|
||||
struct sisfb sc_fb_store;
|
||||
|
||||
struct vcons_data vd;
|
||||
struct wsscreen_list sc_wsl;
|
||||
const struct wsscreen_descr *sc_scrlist[1];
|
||||
int sc_nscr;
|
||||
int sc_mode;
|
||||
};
|
||||
|
||||
int sisfb_match(device_t, cfdata_t, void *);
|
||||
void sisfb_attach(device_t, device_t, void *);
|
||||
|
||||
CFATTACH_DECL_NEW(sisfb, sizeof(struct sisfb_softc),
|
||||
sisfb_match, sisfb_attach, NULL, NULL);
|
||||
|
||||
|
||||
int sisfb_alloc_screen(void *, const struct wsscreen_descr *, void **, int *,
|
||||
int *, long *);
|
||||
void sisfb_free_screen(void *, void *);
|
||||
int sisfb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
|
||||
int sisfb_show_screen(void *, void *, int, void (*)(void *, int, int),
|
||||
void *);
|
||||
paddr_t sisfb_mmap(void *, void *, off_t, int);
|
||||
void sisfb_init_screen(void *, struct vcons_screen *, int, long *);
|
||||
|
||||
|
||||
struct wsdisplay_accessops sisfb_accessops = {
|
||||
sisfb_ioctl,
|
||||
sisfb_mmap,
|
||||
sisfb_alloc_screen,
|
||||
sisfb_free_screen,
|
||||
sisfb_show_screen,
|
||||
NULL, /* load_font */
|
||||
NULL, /* poolc */
|
||||
NULL /* scroll */
|
||||
};
|
||||
|
||||
int sisfb_getcmap(uint8_t *, struct wsdisplay_cmap *);
|
||||
void sisfb_loadcmap(struct sisfb *, int, int);
|
||||
int sisfb_putcmap(uint8_t *, struct wsdisplay_cmap *);
|
||||
int sisfb_setup(struct sisfb *);
|
||||
|
||||
static struct sisfb sisfbcn;
|
||||
|
||||
/*
|
||||
* Control Register access
|
||||
*
|
||||
* These are 8 bit registers; the choice of larger width types is intentional.
|
||||
*/
|
||||
|
||||
#define SIS_VGA_PORT_OFFSET 0x380
|
||||
|
||||
#define SEQ_ADDR (0x3c4 - SIS_VGA_PORT_OFFSET)
|
||||
#define SEQ_DATA (0x3c5 - SIS_VGA_PORT_OFFSET)
|
||||
#define DAC_ADDR (0x3c8 - SIS_VGA_PORT_OFFSET)
|
||||
#define DAC_DATA (0x3c9 - SIS_VGA_PORT_OFFSET)
|
||||
#undef CRTC_ADDR
|
||||
#define CRTC_ADDR (0x3d4 - SIS_VGA_PORT_OFFSET)
|
||||
#define CRTC_DATA (0x3d5 - SIS_VGA_PORT_OFFSET)
|
||||
|
||||
#define CRTC_HDISPLE 0x01 /* horizontal display end */
|
||||
#define CRTC_OVERFLL 0x07 /* overflow low */
|
||||
#define CRTC_STARTADRH 0x0C /* linear start address mid */
|
||||
#define CRTC_STARTADRL 0x0D /* linear start address low */
|
||||
#define CRTC_VDE 0x12 /* vertical display end */
|
||||
|
||||
|
||||
static inline uint sisfb_crtc_read(struct sisfb *, uint);
|
||||
static inline void sisfb_crtc_write(struct sisfb *, uint, uint);
|
||||
static inline uint sisfb_seq_read(struct sisfb *, uint);
|
||||
static inline void sisfb_seq_write(struct sisfb *, uint, uint);
|
||||
|
||||
static inline uint
|
||||
sisfb_crtc_read(struct sisfb *fb, uint idx)
|
||||
{
|
||||
uint val;
|
||||
bus_space_write_1(fb->iot, fb->ioh, CRTC_ADDR, idx);
|
||||
val = bus_space_read_1(fb->iot, fb->ioh, CRTC_DATA);
|
||||
#ifdef SIS_DEBUG
|
||||
printf("CRTC %04x -> %02x\n", idx, val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void
|
||||
sisfb_crtc_write(struct sisfb *fb, uint idx, uint val)
|
||||
{
|
||||
#ifdef SIS_DEBUG
|
||||
printf("CRTC %04x <- %02x\n", idx, val);
|
||||
#endif
|
||||
bus_space_write_1(fb->iot, fb->ioh, CRTC_ADDR, idx);
|
||||
bus_space_write_1(fb->iot, fb->ioh, CRTC_DATA, val);
|
||||
}
|
||||
|
||||
static inline uint
|
||||
sisfb_seq_read(struct sisfb *fb, uint idx)
|
||||
{
|
||||
uint val;
|
||||
bus_space_write_1(fb->iot, fb->ioh, SEQ_ADDR, idx);
|
||||
val = bus_space_read_1(fb->iot, fb->ioh, SEQ_DATA);
|
||||
#ifdef SIS_DEBUG
|
||||
printf("SEQ %04x -> %02x\n", idx, val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void
|
||||
sisfb_seq_write(struct sisfb *fb, uint idx, uint val)
|
||||
{
|
||||
#ifdef SIS_DEBUG
|
||||
printf("SEQ %04x <- %02x\n", idx, val);
|
||||
#endif
|
||||
bus_space_write_1(fb->iot, fb->ioh, SEQ_ADDR, idx);
|
||||
bus_space_write_1(fb->iot, fb->ioh, SEQ_DATA, val);
|
||||
}
|
||||
|
||||
int
|
||||
sisfb_match(device_t parent, cfdata_t match, void *aux)
|
||||
{
|
||||
struct pci_attach_args *pa = (struct pci_attach_args *)aux;
|
||||
|
||||
if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY)
|
||||
return 0;
|
||||
|
||||
if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_SIS)
|
||||
return 0;
|
||||
|
||||
if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SIS_315PRO_VGA)
|
||||
return 100;
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
sisfb_attach(device_t parent, device_t self, void *aux)
|
||||
{
|
||||
struct sisfb_softc *sc = device_private(self);
|
||||
struct pci_attach_args *pa = (struct pci_attach_args *)aux;
|
||||
struct rasops_info *ri;
|
||||
struct wsemuldisplaydev_attach_args waa;
|
||||
bus_size_t fbsize, mmiosize, iosize;
|
||||
struct sisfb *fb;
|
||||
char devinfo[256];
|
||||
int console;
|
||||
unsigned long defattr;
|
||||
|
||||
sc->sc_dev = self;
|
||||
console = sisfbcn.vcs.scr_ri.ri_hw != NULL;
|
||||
|
||||
if (console)
|
||||
fb = &sisfbcn;
|
||||
else {
|
||||
fb = &sc->sc_fb_store;
|
||||
}
|
||||
|
||||
sc->sc_fb = fb;
|
||||
fb->sc = sc;
|
||||
|
||||
pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo));
|
||||
aprint_normal(": %s\n", devinfo);
|
||||
|
||||
if (!console) {
|
||||
fb->fbt = pa->pa_memt;
|
||||
fb->mmiot = pa->pa_memt;
|
||||
fb->iot = pa->pa_iot;
|
||||
if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM,
|
||||
BUS_SPACE_MAP_LINEAR, &fb->fbt, &fb->fbh, NULL, &fbsize) != 0) {
|
||||
aprint_error_dev(self, ": can't map frame buffer\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pci_mapreg_map(pa, PCI_MAPREG_START + 4, PCI_MAPREG_TYPE_MEM,
|
||||
0, &fb->mmiot, &fb->mmioh, NULL, &mmiosize) != 0) {
|
||||
aprint_error_dev(self, ": can't map mmio area\n");
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
if (pci_mapreg_map(pa, PCI_MAPREG_START + 8, PCI_MAPREG_TYPE_IO,
|
||||
0, &fb->iot, &fb->ioh, NULL, &iosize) != 0) {
|
||||
aprint_error_dev(self, ": can't map registers\n");
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
|
||||
if (sisfb_setup(sc->sc_fb) != 0) {
|
||||
aprint_error_dev(self, ": can't setup frame buffer\n");
|
||||
goto fail3;
|
||||
}
|
||||
}
|
||||
|
||||
aprint_normal_dev(self, ": %dx%dx%d frame buffer\n",
|
||||
fb->vcs.scr_ri.ri_width, fb->vcs.scr_ri.ri_height, fb->vcs.scr_ri.ri_depth);
|
||||
|
||||
fb->wsd = (struct wsscreen_descr){
|
||||
"default",
|
||||
0, 0,
|
||||
NULL,
|
||||
8, 16,
|
||||
WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
|
||||
NULL
|
||||
};
|
||||
sc->sc_scrlist[0] = &fb->wsd;
|
||||
sc->sc_wsl = (struct wsscreen_list){1, sc->sc_scrlist};
|
||||
sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
|
||||
|
||||
|
||||
vcons_init(&sc->vd, sc, &fb->wsd, &sisfb_accessops);
|
||||
sc->vd.init_screen = sisfb_init_screen;
|
||||
|
||||
ri = &fb->vcs.scr_ri;
|
||||
if (console) {
|
||||
vcons_init_screen(&sc->vd, &fb->vcs, 1, &defattr);
|
||||
fb->vcs.scr_flags |= VCONS_SCREEN_IS_STATIC;
|
||||
fb->wsd.textops = &ri->ri_ops;
|
||||
fb->wsd.capabilities = ri->ri_caps;
|
||||
fb->wsd.nrows = ri->ri_rows;
|
||||
fb->wsd.ncols = ri->ri_cols;
|
||||
wsdisplay_cnattach(&fb->wsd, ri, 0, 0, defattr);
|
||||
vcons_replay_msgbuf(&fb->vcs);
|
||||
} else {
|
||||
/*
|
||||
* since we're not the console we can postpone the rest
|
||||
* until someone actually allocates a screen for us
|
||||
*/
|
||||
(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
|
||||
}
|
||||
|
||||
waa.console = console;
|
||||
waa.scrdata = &sc->sc_wsl;
|
||||
waa.accessops = &sisfb_accessops;
|
||||
waa.accesscookie = &sc->vd;
|
||||
|
||||
config_found(sc->sc_dev, &waa, wsemuldisplaydevprint);
|
||||
return;
|
||||
|
||||
fail3:
|
||||
bus_space_unmap(fb->iot, fb->ioh, iosize);
|
||||
fail2:
|
||||
bus_space_unmap(fb->mmiot, fb->mmioh, mmiosize);
|
||||
fail1:
|
||||
bus_space_unmap(fb->fbt, fb->fbh, fbsize);
|
||||
}
|
||||
|
||||
/*
|
||||
* wsdisplay accesops
|
||||
*/
|
||||
|
||||
int
|
||||
sisfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
|
||||
int *curxp, int *curyp, long *attrp)
|
||||
{
|
||||
struct sisfb_softc *sc = (struct sisfb_softc *)v;
|
||||
struct rasops_info *ri = &sc->sc_fb->vcs.scr_ri;
|
||||
|
||||
if (sc->sc_nscr > 0)
|
||||
return ENOMEM;
|
||||
|
||||
*cookiep = ri;
|
||||
*curxp = *curyp = 0;
|
||||
ri->ri_ops.allocattr(ri, 0, 0, 0, attrp);
|
||||
sc->sc_nscr++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
sisfb_free_screen(void *v, void *cookie)
|
||||
{
|
||||
struct sisfb_softc *sc = (struct sisfb_softc *)v;
|
||||
|
||||
sc->sc_nscr--;
|
||||
}
|
||||
|
||||
int
|
||||
sisfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flags,
|
||||
struct lwp *l)
|
||||
{
|
||||
struct vcons_data *vd = v;
|
||||
struct sisfb_softc *sc = vd->cookie;
|
||||
struct sisfb *fb = sc->sc_fb;
|
||||
struct rasops_info *ri = &fb->vcs.scr_ri;
|
||||
struct wsdisplay_cmap *cm;
|
||||
struct wsdisplay_fbinfo *wdf;
|
||||
int rc;
|
||||
|
||||
switch (cmd) {
|
||||
case WSDISPLAYIO_GTYPE:
|
||||
*(uint *)data = WSDISPLAY_TYPE_PCIMISC;
|
||||
return 0;
|
||||
case WSDISPLAYIO_GINFO:
|
||||
wdf = (struct wsdisplay_fbinfo *)data;
|
||||
wdf->width = ri->ri_width;
|
||||
wdf->height = ri->ri_height;
|
||||
wdf->depth = ri->ri_depth;
|
||||
wdf->cmsize = 256;
|
||||
return 0;
|
||||
case WSDISPLAYIO_LINEBYTES:
|
||||
*(uint *)data = ri->ri_stride;
|
||||
break;
|
||||
case WSDISPLAYIO_GETCMAP:
|
||||
cm = (struct wsdisplay_cmap *)data;
|
||||
rc = sisfb_getcmap(fb->cmap, cm);
|
||||
return rc;
|
||||
case WSDISPLAYIO_PUTCMAP:
|
||||
cm = (struct wsdisplay_cmap *)data;
|
||||
rc = sisfb_putcmap(fb->cmap, cm);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
if (ri->ri_depth == 8)
|
||||
sisfb_loadcmap(fb, cm->index, cm->count);
|
||||
return 0;
|
||||
}
|
||||
return EPASSTHROUGH;
|
||||
}
|
||||
|
||||
int
|
||||
sisfb_show_screen(void *v, void *cookie, int waitok,
|
||||
void (*cb)(void *, int, int), void *cbarg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
paddr_t
|
||||
sisfb_mmap(void *v, void *vs, off_t offset, int prot)
|
||||
{
|
||||
struct vcons_data *vd = v;
|
||||
struct sisfb_softc *sc = vd->cookie;
|
||||
struct rasops_info *ri = &sc->sc_fb->vcs.scr_ri;
|
||||
|
||||
if ((offset & PAGE_MASK) != 0)
|
||||
return -1;
|
||||
|
||||
if (offset < 0 || offset >= ri->ri_stride * ri->ri_height)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Don't allow mmap if the frame buffer area is not page aligned.
|
||||
* XXX we should reprogram it to a page aligned boundary at attach
|
||||
* XXX time if this isn't the case.
|
||||
*/
|
||||
if (((paddr_t)ri->ri_bits & PAGE_MASK) != 0)
|
||||
return -1;
|
||||
|
||||
/* return XKPHYS_TO_PHYS((paddr_t)ri->ri_bits) + offset; */
|
||||
/* XXX */ return -1;
|
||||
}
|
||||
|
||||
void
|
||||
sisfb_init_screen(void *cookie, struct vcons_screen *scr,
|
||||
int existing, long *defattr)
|
||||
{
|
||||
struct sisfb_softc *sc = cookie;
|
||||
struct sisfb *fb = sc->sc_fb;
|
||||
struct rasops_info *ri = &scr->scr_ri;
|
||||
|
||||
ri->ri_depth = fb->fb_depth;
|
||||
ri->ri_width = fb->fb_width;
|
||||
ri->ri_height = fb->fb_height;
|
||||
ri->ri_stride = fb->fb_stride;
|
||||
ri->ri_flg = RI_CENTER | RI_FULLCLEAR;
|
||||
|
||||
ri->ri_bits = fb->fb_addr;
|
||||
|
||||
if (existing) {
|
||||
ri->ri_flg |= RI_CLEAR;
|
||||
}
|
||||
|
||||
rasops_init(ri, fb->fb_height / 8, fb->fb_width / 8);
|
||||
ri->ri_caps = WSSCREEN_WSCOLORS;
|
||||
rasops_reconfig(ri, fb->fb_height / ri->ri_font->fontheight,
|
||||
fb->fb_width / ri->ri_font->fontwidth);
|
||||
|
||||
ri->ri_hw = scr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Frame buffer initialization.
|
||||
*/
|
||||
|
||||
int
|
||||
sisfb_setup(struct sisfb *fb)
|
||||
{
|
||||
struct rasops_info *ri = &fb->vcs.scr_ri;
|
||||
uint width, height, bpp;
|
||||
bus_size_t fbaddr;
|
||||
uint tmp;
|
||||
|
||||
/*
|
||||
* Unlock access to extended registers.
|
||||
*/
|
||||
|
||||
sisfb_seq_write(fb, 0x05, 0x86);
|
||||
|
||||
/*
|
||||
* Try and figure out display settings.
|
||||
*/
|
||||
|
||||
height = sisfb_crtc_read(fb, CRTC_VDE);
|
||||
tmp = sisfb_crtc_read(fb, CRTC_OVERFLL);
|
||||
if (ISSET(tmp, 1 << 1))
|
||||
height |= 1 << 8;
|
||||
if (ISSET(tmp, 1 << 6))
|
||||
height |= 1 << 9;
|
||||
tmp = sisfb_seq_read(fb, 0x0a);
|
||||
if (ISSET(tmp, 1 << 1))
|
||||
height |= 1 << 10;
|
||||
height++;
|
||||
|
||||
width = sisfb_crtc_read(fb, CRTC_HDISPLE);
|
||||
tmp = sisfb_seq_read(fb, 0x0b);
|
||||
if (ISSET(tmp, 1 << 2))
|
||||
width |= 1 << 8;
|
||||
if (ISSET(tmp, 1 << 3))
|
||||
width |= 1 << 9;
|
||||
width++;
|
||||
width <<= 3;
|
||||
|
||||
#ifdef SIS_DEBUG
|
||||
printf("height %d width %d\n", height, width);
|
||||
#endif
|
||||
|
||||
fbaddr = sisfb_crtc_read(fb, CRTC_STARTADRL) |
|
||||
(sisfb_crtc_read(fb, CRTC_STARTADRH) << 8) |
|
||||
(sisfb_seq_read(fb, 0x0d) << 16) |
|
||||
((sisfb_seq_read(fb, 0x37) & 0x03) << 24);
|
||||
fbaddr <<= 2;
|
||||
#ifdef SIS_DEBUG
|
||||
printf("FBADDR %lx\n", fbaddr);
|
||||
#endif
|
||||
|
||||
tmp = sisfb_seq_read(fb, 0x06);
|
||||
switch (tmp & 0x1c) {
|
||||
case 0x00:
|
||||
bpp = 8;
|
||||
break;
|
||||
case 0x04:
|
||||
bpp = 15;
|
||||
break;
|
||||
case 0x08:
|
||||
bpp = 16;
|
||||
break;
|
||||
case 0x10:
|
||||
bpp = 32;
|
||||
break;
|
||||
default:
|
||||
aprint_error("unknown bpp for 0x%x\n", tmp);
|
||||
return EINVAL;
|
||||
}
|
||||
#ifdef SIS_DEBUG
|
||||
printf("BPP %d\n", bpp);
|
||||
#endif
|
||||
|
||||
fb->fb_width = ri->ri_width = width;
|
||||
fb->fb_height = ri->ri_height = height;
|
||||
fb->fb_depth = ri->ri_depth = bpp;
|
||||
fb->fb_stride = ri->ri_stride = (ri->ri_width * ri->ri_depth) / 8;
|
||||
ri->ri_flg = /* RI_CENTER | RI_CLEAR | RI_FULLCLEAR */ RI_CENTER | RI_NO_AUTO;
|
||||
fb->fb_addr = ri->ri_bits =
|
||||
(void *)((char *)bus_space_vaddr(fb->fbt, fb->fbh) + fbaddr);
|
||||
ri->ri_hw = fb;
|
||||
|
||||
#ifdef SIS_DEBUG
|
||||
printf("ri_bits %p\n", ri->ri_bits);
|
||||
#endif
|
||||
|
||||
#ifdef __MIPSEL__
|
||||
/* swap B and R */
|
||||
switch (bpp) {
|
||||
case 15:
|
||||
ri->ri_rnum = 5;
|
||||
ri->ri_rpos = 10;
|
||||
ri->ri_gnum = 5;
|
||||
ri->ri_gpos = 5;
|
||||
ri->ri_bnum = 5;
|
||||
ri->ri_bpos = 0;
|
||||
break;
|
||||
case 16:
|
||||
ri->ri_rnum = 5;
|
||||
ri->ri_rpos = 11;
|
||||
ri->ri_gnum = 6;
|
||||
ri->ri_gpos = 5;
|
||||
ri->ri_bnum = 5;
|
||||
ri->ri_bpos = 0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
bcopy(rasops_cmap, fb->cmap, sizeof(fb->cmap));
|
||||
if (bpp == 8) {
|
||||
sisfb_loadcmap(fb, 0, 256);
|
||||
}
|
||||
|
||||
rasops_init(ri, 30, 80);
|
||||
rasops_reconfig(ri, ri->ri_height / ri->ri_font->fontheight,
|
||||
ri->ri_width / ri->ri_font->fontwidth);
|
||||
|
||||
fb->wsd.name = "std";
|
||||
fb->wsd.ncols = ri->ri_cols;
|
||||
fb->wsd.nrows = ri->ri_rows;
|
||||
fb->wsd.textops = &ri->ri_ops;
|
||||
fb->wsd.fontwidth = ri->ri_font->fontwidth;
|
||||
fb->wsd.fontheight = ri->ri_font->fontheight;
|
||||
fb->wsd.capabilities = ri->ri_caps;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Colormap handling routines.
|
||||
*/
|
||||
|
||||
void
|
||||
sisfb_loadcmap(struct sisfb *fb, int baseidx, int count)
|
||||
{
|
||||
uint8_t *cmap = fb->cmap + baseidx * 3;
|
||||
|
||||
bus_space_write_1(fb->iot, fb->ioh, DAC_ADDR, baseidx);
|
||||
while (count-- != 0) {
|
||||
bus_space_write_1(fb->iot, fb->ioh, DAC_DATA, *cmap++ >> 2);
|
||||
bus_space_write_1(fb->iot, fb->ioh, DAC_DATA, *cmap++ >> 2);
|
||||
bus_space_write_1(fb->iot, fb->ioh, DAC_DATA, *cmap++ >> 2);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
sisfb_getcmap(uint8_t *cmap, struct wsdisplay_cmap *cm)
|
||||
{
|
||||
uint index = cm->index, count = cm->count, i;
|
||||
uint8_t ramp[256], *dst, *src;
|
||||
int rc;
|
||||
|
||||
if (index >= 256 || count > 256 - index)
|
||||
return EINVAL;
|
||||
|
||||
index *= 3;
|
||||
|
||||
src = cmap + index;
|
||||
dst = ramp;
|
||||
for (i = 0; i < count; i++)
|
||||
*dst++ = *src, src += 3;
|
||||
rc = copyout(ramp, cm->red, count);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
src = cmap + index + 1;
|
||||
dst = ramp;
|
||||
for (i = 0; i < count; i++)
|
||||
*dst++ = *src, src += 3;
|
||||
rc = copyout(ramp, cm->green, count);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
src = cmap + index + 2;
|
||||
dst = ramp;
|
||||
for (i = 0; i < count; i++)
|
||||
*dst++ = *src, src += 3;
|
||||
rc = copyout(ramp, cm->blue, count);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sisfb_putcmap(uint8_t *cmap, struct wsdisplay_cmap *cm)
|
||||
{
|
||||
uint index = cm->index, count = cm->count, i;
|
||||
uint8_t ramp[256], *dst, *src;
|
||||
int rc;
|
||||
|
||||
if (index >= 256 || count > 256 - index)
|
||||
return EINVAL;
|
||||
|
||||
index *= 3;
|
||||
|
||||
rc = copyin(cm->red, ramp, count);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
dst = cmap + index;
|
||||
src = ramp;
|
||||
for (i = 0; i < count; i++)
|
||||
*dst = *src++, dst += 3;
|
||||
|
||||
rc = copyin(cm->green, ramp, count);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
dst = cmap + index + 1;
|
||||
src = ramp;
|
||||
for (i = 0; i < count; i++)
|
||||
*dst = *src++, dst += 3;
|
||||
|
||||
rc = copyin(cm->blue, ramp, count);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
dst = cmap + index + 2;
|
||||
src = ramp;
|
||||
for (i = 0; i < count; i++)
|
||||
*dst = *src++, dst += 3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Early console code
|
||||
*/
|
||||
|
||||
int
|
||||
sisfb_cnattach(bus_space_tag_t memt, bus_space_tag_t iot,
|
||||
pci_chipset_tag_t pc, pcitag_t tag, pcireg_t id)
|
||||
{
|
||||
long defattr;
|
||||
struct rasops_info * const ri = &sisfbcn.vcs.scr_ri;
|
||||
pcireg_t bar;
|
||||
int rc;
|
||||
|
||||
|
||||
/* filter out unrecognized devices */
|
||||
switch (id) {
|
||||
default:
|
||||
return ENODEV;
|
||||
case PCI_ID_CODE(PCI_VENDOR_SIS, PCI_PRODUCT_SIS_315PRO_VGA):
|
||||
break;
|
||||
}
|
||||
|
||||
bar = pci_conf_read(pc, tag, PCI_MAPREG_START);
|
||||
if (PCI_MAPREG_TYPE(bar) != PCI_MAPREG_TYPE_MEM)
|
||||
return EINVAL;
|
||||
sisfbcn.fbt = memt;
|
||||
rc = bus_space_map(memt, PCI_MAPREG_MEM_ADDR(bar), 1 /* XXX */,
|
||||
BUS_SPACE_MAP_LINEAR, &sisfbcn.fbh);
|
||||
#ifdef SIS_DEBUG
|
||||
printf("sisfb_cnattach(memt, 0x%x rc %d\n", PCI_MAPREG_MEM_ADDR(bar), rc);
|
||||
#endif
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
bar = pci_conf_read(pc, tag, PCI_MAPREG_START + 4);
|
||||
if (PCI_MAPREG_TYPE(bar) != PCI_MAPREG_TYPE_MEM)
|
||||
return EINVAL;
|
||||
sisfbcn.mmiot = memt;
|
||||
rc = bus_space_map(memt, PCI_MAPREG_MEM_ADDR(bar), 1 /* XXX */,
|
||||
BUS_SPACE_MAP_LINEAR, &sisfbcn.mmioh);
|
||||
#ifdef SIS_DEBUG
|
||||
printf("sisfb_cnattach(memt2, 0x%x rc %d\n", PCI_MAPREG_MEM_ADDR(bar), rc);
|
||||
#endif
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
bar = pci_conf_read(pc, tag, PCI_MAPREG_START + 8);
|
||||
if (PCI_MAPREG_TYPE(bar) != PCI_MAPREG_TYPE_IO)
|
||||
return EINVAL;
|
||||
sisfbcn.iot = iot;
|
||||
rc = bus_space_map(iot, PCI_MAPREG_MEM_ADDR(bar), 1 /* XXX */,
|
||||
0, &sisfbcn.ioh);
|
||||
#ifdef SIS_DEBUG
|
||||
printf("sisfb_cnattach(iot, 0x%x rc %d\n", PCI_MAPREG_MEM_ADDR(bar), rc);
|
||||
#endif
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
rc = sisfb_setup(&sisfbcn);
|
||||
#ifdef SIS_DEBUG
|
||||
printf("sisfb_setup %d %p\n", rc, sisfbcn.vcs.scr_ri.ri_hw);
|
||||
#endif
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
ri->ri_ops.allocattr(ri, 0, ri->ri_rows - 1, 0, &defattr);
|
||||
wsdisplay_preattach(&sisfbcn.wsd, ri, 0, 0, defattr);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
/* $NetBSD: sisfb.h,v 1.1 2011/08/27 13:28:37 bouyer Exp $ */
|
||||
int sisfb_cnattach(bus_space_tag_t, bus_space_tag_t, pci_chipset_tag_t,
|
||||
pcitag_t, pcireg_t);
|
Loading…
Reference in New Issue