diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2006-04-16 20:45:01 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2006-04-16 20:45:01 +0000 |
commit | d105cf31eb9e601911439f943234005022f2fffc (patch) | |
tree | c5c2177e2819abafb0a582108c557f96bfd95ac0 /sys/dev/pcmcia | |
parent | 9814cc09896824c76461742feedf2a2faf252afb (diff) |
Preliminary driver for the Colorgraphic VoyagerVGA pcmcia frame buffer;
more like a proof of concept than anything useful, due to the slowness of the
beast, but deraadt@ insists this gets in the tree.
Written with matthieu@'s help.
Diffstat (limited to 'sys/dev/pcmcia')
-rw-r--r-- | sys/dev/pcmcia/cfxga.c | 896 | ||||
-rw-r--r-- | sys/dev/pcmcia/cfxgareg.h | 55 | ||||
-rw-r--r-- | sys/dev/pcmcia/files.pcmcia | 7 |
3 files changed, 957 insertions, 1 deletions
diff --git a/sys/dev/pcmcia/cfxga.c b/sys/dev/pcmcia/cfxga.c new file mode 100644 index 00000000000..1eca9c713ec --- /dev/null +++ b/sys/dev/pcmcia/cfxga.c @@ -0,0 +1,896 @@ +/* $OpenBSD: cfxga.c,v 1.1 2006/04/16 20:45:00 miod Exp $ */ + +/* + * Copyright (c) 2005 Matthieu Herrb and 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. + */ + +/* + * Work-in-progress display driver for the Colorgraphic CompactFlash + * ``VoyagerVGA'' card. + * + * Our goals are: + * - to provide a somewhat usable emulation mode for extra text display. + * - to let an application (such as an X server) map the controller registers + * in order to do its own display game. + * + * Driving this card is somewhat a challenge since: + * - its video memory is not directly accessible. + * - no operation can make use of DMA. + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/conf.h> + +#include <dev/pcmcia/pcmciavar.h> +#include <dev/pcmcia/pcmciareg.h> + +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> +#include <dev/rasops/rasops.h> + +#include <dev/pcmcia/cfxgareg.h> + +/* #define CFXGADEBUG */ + +#ifdef CFXGADEBUG +#define DPRINTF(arg) printf arg +#else +#define DPRINTF(arg) +#endif + +struct cfxga_screen; + +struct cfxga_softc { + struct device sc_dev; + struct pcmcia_function *sc_pf; + int sc_state; +#define CS_MAPPED 0x0001 +#define CS_RESET 0x0002 + + struct pcmcia_mem_handle sc_pmemh; + int sc_memwin; + bus_addr_t sc_offset; + + int sc_mode; + + int sc_nscreens; + LIST_HEAD(, cfxga_screen) sc_scr; + struct cfxga_screen *sc_active; + + struct device *sc_wsd; +}; + +int cfxga_match(struct device *, void *, void *); +void cfxga_attach(struct device *, struct device *, void *); +int cfxga_detach(struct device *, int); +int cfxga_activate(struct device *, enum devact); + +struct cfattach cfxga_ca = { + sizeof(struct cfxga_softc), cfxga_match, cfxga_attach, + cfxga_detach, cfxga_activate +}; + +struct cfdriver cfxga_cd = { + NULL, "cfxga", DV_DULL +}; + +int cfxga_alloc_screen(void *, const struct wsscreen_descr *, void **, + int *, int *, long *); +void cfxga_burner(void *, u_int, u_int); +void cfxga_free_screen(void *, void *); +int cfxga_ioctl(void *, u_long, caddr_t, int, struct proc *); +paddr_t cfxga_mmap(void *, off_t, int); +int cfxga_show_screen(void *, void *, int, void (*)(void *, int, int), + void *); + +struct wsdisplay_accessops cfxga_accessops = { + cfxga_ioctl, + cfxga_mmap, + cfxga_alloc_screen, + cfxga_free_screen, + cfxga_show_screen, + NULL, + NULL, + NULL, + cfxga_burner +}; + +struct wsscreen_descr cfxga_scr = { + "std" +}; + +const struct wsscreen_descr *cfxga_scr_descr[] = { + &cfxga_scr +}; + +const struct wsscreen_list cfxga_scr_list = { + sizeof cfxga_scr_descr / sizeof cfxga_scr_descr[0], + cfxga_scr_descr +}; + +/* + * Per-screen structure + */ + +struct cfxga_screen { + LIST_ENTRY(cfxga_screen) scr_link; + + /* parent reference */ + struct cfxga_softc *scr_sc; + + /* raster op glue */ + struct rasops_info scr_ri; + struct wsdisplay_emulops scr_ops; /* old ri_ops */ + void (*scr_do_cursor)(struct rasops_info *); /* old ri_do_cursor */ + + /* backing memory */ + u_int8_t *scr_mem; +}; + +void cfxga_copycols(void *, int, int, int, int); +void cfxga_copyrows(void *, int, int, int); +void cfxga_do_cursor(struct rasops_info *); +void cfxga_erasecols(void *, int, int, int, long); +void cfxga_eraserows(void *, int, int, long); +void cfxga_putchar(void *, int, int, u_int, long); + +int cfxga_install_function(struct pcmcia_function *); +int cfxga_memory_rop(struct cfxga_softc *, struct cfxga_screen *, u_int, + int, int, int, int); +void cfxga_remove_function(struct pcmcia_function *); +void cfxga_reset_video(struct cfxga_softc *); +void cfxga_reset_and_repaint(struct cfxga_softc *); +int cfxga_standalone_rop(struct cfxga_softc *, u_int, int, int, int, int, + u_int16_t); +u_int cfxga_wait(struct cfxga_softc *, u_int, u_int); + +#define cfxga_clear_screen(sc) \ + cfxga_standalone_rop(sc, CROP_SOLIDFILL, 0, 0, 640, 480, 0) +#define cfxga_repaint_screen(sc) \ + cfxga_memory_rop(sc, sc->sc_active, CROP_EXTCOPY, 0, 0, 640, 480) + +#define cfxga_read(sc, addr) \ + bus_space_read_2((sc)->sc_pmemh.memt, (sc)->sc_pmemh.memh, \ + (sc)->sc_offset + (addr)) +#define cfxga_write(sc, addr, val) \ + bus_space_write_2((sc)->sc_pmemh.memt, (sc)->sc_pmemh.memh, \ + (sc)->sc_offset + (addr), (val)) + +/* + * This card is very poorly engineered, specificationwise. It does not + * provide any CIS information, and has no vendor/product numbers as + * well: as such, there is no easy way to differentiate it from any + * other cheapo PCMCIA card. + * + * The best we can do is probe for a chip ID. This is not perfect but better + * than matching blindly. Of course this requires us to play some nasty games + * behind the PCMCIA framework to be able to do this probe, and correctly fail + * if this is not the card we are looking for. + * + * In shorter words: some card designers ought to be shot, as a service + * to the community. + */ + +/* + * Create the necessary pcmcia function structures to alleviate the lack + * of any CIS information on this device. + * Actually, we hijack the fake function created by the pcmcia framework. + */ +int +cfxga_install_function(struct pcmcia_function *pf) +{ + struct pcmcia_config_entry *cfe; + + /* Get real. */ + pf->pf_flags &= ~PFF_FAKE; + + /* Tell the pcmcia framework where the CCR is. */ + pf->ccr_base = 0x800; + pf->ccr_mask = 0x67; + + /* Create a simple cfe. */ + cfe = (struct pcmcia_config_entry *)malloc(sizeof *cfe, + M_DEVBUF, M_NOWAIT); + if (cfe == NULL) { + DPRINTF(("%s: cfe allocation failed\n", __func__)); + return (ENOMEM); + } + + bzero(cfe, sizeof *cfe); + cfe->number = 42; /* have to put some value... */ + cfe->flags = PCMCIA_CFE_IO16; + cfe->iftype = PCMCIA_IFTYPE_MEMORY; + + SIMPLEQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list); + + pcmcia_function_init(pf, cfe); + return (0); +} + +/* + * Undo the changes done above. + * Such a function is necessary since we need a full-blown pcmcia world + * set up in order to do the device probe, but if we don't match the card, + * leaving this state will cause trouble during other probes. + */ +void +cfxga_remove_function(struct pcmcia_function *pf) +{ + struct pcmcia_config_entry *cfe; + + /* we are the first and only entry... */ + cfe = SIMPLEQ_FIRST(&pf->cfe_head); + SIMPLEQ_REMOVE_HEAD(&pf->cfe_head, cfe_list); + free(cfe, M_DEVBUF); + + /* And we're a figment of the kernel's imagination again. */ + pf->pf_flags |= PFF_FAKE; +} + +int +cfxga_match(struct device *parent, void *match, void *aux) +{ + struct pcmcia_attach_args *pa = aux; + struct pcmcia_function *pf = pa->pf; + struct pcmcia_mem_handle h; + int rc; + int win; + bus_addr_t ptr; + u_int8_t id = 0; + + if (pa->product != PCMCIA_PRODUCT_INVALID || + pa->manufacturer != PCMCIA_VENDOR_INVALID) + return (0); + + /* Only a card with no CIS will have a fake function... */ + if ((pf->pf_flags & PFF_FAKE) == 0) + return (0); + + if (cfxga_install_function(pf) != 0) + return (0); + + if (pcmcia_function_enable(pf) != 0) { + DPRINTF(("%s: function enable failed\n")); + return (0); + } + + rc = pcmcia_mem_alloc(pf, CFXGA_MEM_RANGE, &h); + if (rc != 0) + goto out; + + rc = pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, 0, CFXGA_MEM_RANGE, + &h, &ptr, &win); + if (rc != 0) + goto out2; + + id = bus_space_read_1(h.memt, h.memh, ptr) & CR_ID_MASK; + + pcmcia_mem_unmap(pa->pf, win); +out2: + pcmcia_mem_free(pa->pf, &h); +out: + pcmcia_function_disable(pf); + cfxga_remove_function(pf); + + /* + * Be sure to return a value greater than pccom's if we match, + * otherwise it can win due to the way config(8) will order devices... + */ + return (id == CR_ID ? 10 : 0); +} + +int +cfxga_activate(struct device *dev, enum devact act) +{ + struct cfxga_softc *sc = (void *)dev; + + switch (act) { + case DVACT_ACTIVATE: + if (pcmcia_function_enable(sc->sc_pf) != 0) { + printf("%s: function enable failed\n", + sc->sc_dev.dv_xname); + } else { + cfxga_reset_and_repaint(sc); + } + break; + case DVACT_DEACTIVATE: + pcmcia_function_disable(sc->sc_pf); + break; + } + return (0); +} + +void +cfxga_attach(struct device *parent, struct device *self, void *aux) +{ + struct cfxga_softc *sc = (void *)self; + struct pcmcia_attach_args *pa = aux; + struct pcmcia_function *pf = pa->pf; + struct wsemuldisplaydev_attach_args waa; + + LIST_INIT(&sc->sc_scr); + sc->sc_nscreens = 0; + sc->sc_pf = pf; + + if (cfxga_install_function(pf) != 0) { + printf(": pcmcia function setup failed\n"); + return; + } + + if (pcmcia_function_enable(pf)) { + printf(": function enable failed\n"); + return; + } + + if (pcmcia_mem_alloc(pf, CFXGA_MEM_RANGE, &sc->sc_pmemh) != 0) { + printf(": can't allocate memory space\n"); + return; + } + + if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, 0, CFXGA_MEM_RANGE, + &sc->sc_pmemh, &sc->sc_offset, &sc->sc_memwin) != 0) { + printf(": can't map frame buffer registers\n"); + pcmcia_mem_free(pf, &sc->sc_pmemh); + return; + } + + SET(sc->sc_state, CS_MAPPED); + + printf("\n"); + + sc->sc_mode = WSDISPLAYIO_MODE_EMUL; + + cfxga_reset_video(sc); + + waa.console = 0; + waa.scrdata = &cfxga_scr_list; + waa.accessops = &cfxga_accessops; + waa.accesscookie = sc; + + if ((sc->sc_wsd = config_found(self, &waa, wsemuldisplaydevprint)) == + NULL) + cfxga_clear_screen(sc); /* otherwise wscons will do this */ +} + +int +cfxga_detach(struct device *dev, int flags) +{ + struct cfxga_softc *sc = (void *)dev; + + /* + * Detach all children, and hope wsdisplay detach code is correct... + */ + if (sc->sc_wsd != NULL) { + config_detach(sc->sc_wsd, DETACH_FORCE); + /* sc->sc_wsd = NULL; */ + } + + if (ISSET(sc->sc_state, CS_MAPPED)) { + pcmcia_mem_unmap(sc->sc_pf, sc->sc_memwin); + pcmcia_mem_free(sc->sc_pf, &sc->sc_pmemh); + /* CLR(sc->sc_state, CS_MAPPED); */ + } + + return (0); +} + +/* + * Wscons operations + */ + +int +cfxga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, + int *curxp, int *curyp, long *attrp) +{ + struct cfxga_softc *sc = v; + struct cfxga_screen *scr; + struct rasops_info *ri; + + scr = malloc(sizeof *scr, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); + if (scr == NULL) + return (ENOMEM); + bzero(scr, sizeof *scr); + + scr->scr_mem = malloc(640 * 480 * 16 / 8, M_DEVBUF, + cold ? M_NOWAIT : M_WAITOK); + if (scr->scr_mem == NULL) { + free(scr, M_DEVBUF); + return (ENOMEM); + } + bzero(scr->scr_mem, 640 * 480 * 16 / 8); + + ri = &scr->scr_ri; + ri->ri_hw = (void *)scr; + ri->ri_bits = scr->scr_mem; + ri->ri_depth = 16; + ri->ri_width = 640; + ri->ri_height = 480; + ri->ri_stride = 640 * 16 / 8; + /* ri->ri_flg = RI_FULLCLEAR; */ + + /* swap B and R */ + ri->ri_rnum = 5; + ri->ri_rpos = 11; + ri->ri_gnum = 6; + ri->ri_gpos = 5; + ri->ri_bnum = 5; + ri->ri_bpos = 0; + + if (cfxga_scr.nrows == 0) { + rasops_init(ri, 100, 100); + + cfxga_scr.nrows = ri->ri_rows; + cfxga_scr.ncols = ri->ri_cols; + cfxga_scr.capabilities = ri->ri_caps; + cfxga_scr.textops = &ri->ri_ops; + } else { + rasops_init(ri, cfxga_scr.nrows, cfxga_scr.ncols); + } + + scr->scr_ops = ri->ri_ops; + ri->ri_ops.copycols = cfxga_copycols; + ri->ri_ops.copyrows = cfxga_copyrows; + ri->ri_ops.erasecols = cfxga_erasecols; + ri->ri_ops.eraserows = cfxga_eraserows; + ri->ri_ops.putchar = cfxga_putchar; + scr->scr_do_cursor = ri->ri_do_cursor; + ri->ri_do_cursor = cfxga_do_cursor; + + scr->scr_sc = sc; + LIST_INSERT_HEAD(&sc->sc_scr, scr, scr_link); + sc->sc_nscreens++; + + ri->ri_ops.alloc_attr(ri, 0, 0, 0, attrp); + + *cookiep = ri; + *curxp = *curyp = 0; + + return (0); +} + +void +cfxga_burner(void *v, u_int on, u_int flags) +{ + struct cfxga_softc *sc = (void *)v; + u_int16_t ven; + + ven = cfxga_read(sc, CFREG_VIDEO); + + if (on) + cfxga_write(sc, CFREG_VIDEO, ven | CV_VIDEO_VGA); + else + cfxga_write(sc, CFREG_VIDEO, ven & ~CV_VIDEO_VGA); +} + +void +cfxga_free_screen(void *v, void *cookie) +{ + struct cfxga_softc *sc = v; + struct rasops_info *ri = cookie; + struct cfxga_screen *scr = ri->ri_hw; + + LIST_REMOVE(scr, scr_link); + sc->sc_nscreens--; + + if (scr == sc->sc_active) { + sc->sc_active = NULL; + cfxga_burner(sc, 0, 0); + } + + free(scr->scr_mem, M_DEVBUF); + free(scr, M_DEVBUF); +} + +int +cfxga_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + struct cfxga_softc *sc = v; + struct wsdisplay_fbinfo *wdf; + int mode; + + switch (cmd) { + case WSDISPLAYIO_GTYPE: + *(u_int *)data = WSDISPLAY_TYPE_CFXGA; + break; + + case WSDISPLAYIO_GINFO: + /* it's not worth using sc->sc_active->scr_ri fields... */ + wdf = (struct wsdisplay_fbinfo *)data; + wdf->height = 640; + wdf->width = 480; + wdf->depth = 16; + wdf->cmsize = 0; + break; + + case WSDISPLAYIO_SMODE: + mode = *(u_int *)data; + if (mode == sc->sc_mode) + break; + switch (mode) { + case WSDISPLAYIO_MODE_EMUL: + cfxga_reset_and_repaint(sc); + break; + case WSDISPLAYIO_MODE_MAPPED: + break; + default: + return (EINVAL); + } + sc->sc_mode = mode; + break; + + /* these operations are handled by the wscons code... */ + case WSDISPLAYIO_GVIDEO: + case WSDISPLAYIO_SVIDEO: + break; + + /* these operations are not supported... */ + case WSDISPLAYIO_GETCMAP: + case WSDISPLAYIO_PUTCMAP: + case WSDISPLAYIO_LINEBYTES: + case WSDISPLAYIO_GCURPOS: + case WSDISPLAYIO_SCURPOS: + case WSDISPLAYIO_GCURMAX: + case WSDISPLAYIO_GCURSOR: + case WSDISPLAYIO_SCURSOR: + default: + return (-1); + } + + return (0); +} + +paddr_t +cfxga_mmap(void *v, off_t off, int prot) +{ + return (-1); +} + +int +cfxga_show_screen(void *v, void *cookie, int waitok, + void (*cb)(void *, int, int), void *cbarg) +{ + struct cfxga_softc *sc = v; + struct rasops_info *ri = cookie; + struct cfxga_screen *scr = ri->ri_hw, *old; + + old = sc->sc_active; + if (old == scr) + return (0); + + sc->sc_active = scr; + cfxga_repaint_screen(sc); + + /* turn back video on as well if necessary... */ + if (old == NULL) + cfxga_burner(sc, 1, 0); + + return (0); +} + +/* + * Real frame buffer operations + */ + +void +cfxga_reset_video(struct cfxga_softc *sc) +{ + /* reset controller */ + cfxga_write(sc, CFREG_BLT_CTRL, 0); + cfxga_write(sc, CFREG_RESET, CR_RESET); + delay(25000); + cfxga_write(sc, CFREG_RESET, 0); + delay(25000); + cfxga_write(sc, CFREG_BLT_CTRL, 0); + (void)cfxga_read(sc, CFREG_BLT_DATA); + + /* + * Setup video mode - magic values taken from the linux so-called + * driver source. + */ + + /* clock */ + cfxga_write(sc, 0x10, 2); + cfxga_write(sc, 0x14, 0); + cfxga_write(sc, 0x1c, 2); + /* memory configuration */ + cfxga_write(sc, 0x20, 0x0380); + cfxga_write(sc, 0x2a, 0x100); + /* CRT and TV settings */ + cfxga_write(sc, 0x62, 0); + cfxga_write(sc, 0x64, 0); + cfxga_write(sc, 0x68, 0); + cfxga_write(sc, 0x6a, 0); + /* cursor */ + cfxga_write(sc, 0x80, 0); + cfxga_write(sc, 0x82, 0x259); + cfxga_write(sc, 0x84, 0x190); + cfxga_write(sc, 0x86, 0); + cfxga_write(sc, 0x88, 0); + cfxga_write(sc, 0x8a, 0x3f1f); + cfxga_write(sc, 0x8c, 0x1f); + cfxga_write(sc, 0x8e, 0); + /* unknown */ + cfxga_write(sc, 0x1f0, 0x210); + cfxga_write(sc, 0x1f4, 0); + + /* 640x480x72x16 specific values */ + /* gpio */ + cfxga_write(sc, 0x04, 0x07); + cfxga_write(sc, 0x08, 0x1ffe); + /* more clock */ + cfxga_write(sc, 0x18, 0); + cfxga_write(sc, 0x1e, 2); + /* more CRT and TV settings */ + cfxga_write(sc, 0x50, 0x4f); + cfxga_write(sc, 0x52, 0x217); + cfxga_write(sc, 0x54, 0x4); + cfxga_write(sc, 0x56, 0x1df); + cfxga_write(sc, 0x58, 0x827); + cfxga_write(sc, 0x5a, 0x1202); + cfxga_write(sc, 0x60, 5); + cfxga_write(sc, 0x66, 640); + + cfxga_write(sc, CFREG_VIDEO, CV_VIDEO_VGA); + delay(25000); +} + +void +cfxga_reset_and_repaint(struct cfxga_softc *sc) +{ + cfxga_reset_video(sc); + if (sc->sc_active != NULL) + cfxga_repaint_screen(sc); + else + cfxga_clear_screen(sc); +} + +u_int +cfxga_wait(struct cfxga_softc *sc, u_int mask, u_int result) +{ + u_int tries; + + for (tries = 100000; tries != 0; tries--) { + if ((bus_space_read_1(sc->sc_pmemh.memt, sc->sc_pmemh.memh, + sc->sc_offset + CFREG_BLT_CTRL) & mask) == result) + break; + delay(10); + } + + return (tries); +} + +int +cfxga_memory_rop(struct cfxga_softc *sc, struct cfxga_screen *scr, u_int rop, + int x, int y, int cx, int cy) +{ + u_int pos; + u_int16_t *data; + + pos = (y * 640 + x) * (16 / 8); + data = (u_int16_t *)(scr->scr_mem + pos); + + if (cfxga_wait(sc, CC_BLT_BUSY, 0) == 0) { + DPRINTF(("%s: not ready\n", __func__)); + if (ISSET(sc->sc_state, CS_RESET)) + return (EAGAIN); + else { + DPRINTF(("%s: resetting...\n", sc->sc_dev.dv_xname)); + SET(sc->sc_state, CS_RESET); + cfxga_reset_and_repaint(sc); + CLR(sc->sc_state, CS_RESET); + return (0); + } + } + (void)cfxga_read(sc, CFREG_BLT_DATA); + + cfxga_write(sc, CFREG_BLT_ROP, rop); + cfxga_write(sc, CFREG_BLT_UNK1, 0); + cfxga_write(sc, CFREG_BLT_UNK2, 0); + cfxga_write(sc, CFREG_BLT_SRCLOW, pos); + cfxga_write(sc, CFREG_BLT_SRCHIGH, pos >> 16); + cfxga_write(sc, CFREG_BLT_STRIDE, 640); + cfxga_write(sc, CFREG_BLT_WIDTH, cx - 1); + cfxga_write(sc, CFREG_BLT_HEIGHT, cy - 1); + cfxga_write(sc, CFREG_BLT_CTRL, CC_BLT_BUSY | CC_BPP_16); + + (void)cfxga_wait(sc, CC_BLT_BUSY, CC_BLT_BUSY); + while (cy-- != 0) { + for (x = 0; x < cx; x++) { + cfxga_write(sc, CFREG_BLT_DATA, *data++); + + /* + * Let the cheap breathe. + * If this is not enough to let it recover, + * abort the operation. + */ + if (cfxga_wait(sc, CC_FIFO_BUSY, 0) == 0) { + DPRINTF(("%s: abort\n", __func__)); + cfxga_write(sc, CFREG_BLT_CTRL, 0); + return (EINTR); + } + } + data += (640 - cx); + } + + return (0); +} + +int +cfxga_standalone_rop(struct cfxga_softc *sc, u_int rop, int x, int y, + int cx, int cy, u_int16_t srccolor) +{ + u_int pos; + + pos = (y * 640 + x) * (16 / 8); + + if (cfxga_wait(sc, CC_BLT_BUSY, 0) == 0) { + DPRINTF(("%s: not ready\n", __func__)); + if (ISSET(sc->sc_state, CS_RESET)) + return (EAGAIN); + else { + DPRINTF(("%s: resetting...\n", sc->sc_dev.dv_xname)); + SET(sc->sc_state, CS_RESET); + cfxga_reset_and_repaint(sc); + CLR(sc->sc_state, CS_RESET); + return (0); + } + } + + cfxga_write(sc, CFREG_BLT_ROP, rop); + cfxga_write(sc, CFREG_BLT_UNK1, 0); + cfxga_write(sc, CFREG_BLT_UNK2, 0); + cfxga_write(sc, CFREG_BLT_SRCLOW, pos); + cfxga_write(sc, CFREG_BLT_SRCHIGH, pos >> 16); + cfxga_write(sc, CFREG_BLT_STRIDE, 640); + cfxga_write(sc, CFREG_BLT_WIDTH, cx - 1); + cfxga_write(sc, CFREG_BLT_HEIGHT, cy - 1); + cfxga_write(sc, CFREG_BLT_SRCCOLOR, srccolor); + cfxga_write(sc, CFREG_BLT_CTRL, CC_BLT_BUSY | CC_BPP_16); + + return (0); +} + +/* + * Text console raster operations + * + * For all operations, we need first to run them on the memory frame buffer + * (by means of the rasops primitives), then decide what to send to the + * controller. + * + * For now we end up sending every operation to the device. But this could + * be improved, based on actual knowledge of what sequences of operations + * the wscons emulations perform. This is far from trivial... + * + * Another approach worth trying would be to use a timeout and reblt the + * whole screen if it has changed, i.e. set a flag in all raster op routines + * below, and have the timeout callback do a blt if the flag is set. + * However, since a whole blt takes close to a second (or maybe more) it + * is probably not a good idea. + */ + +void +cfxga_copycols(void *cookie, int row, int src, int dst, int num) +{ + struct rasops_info *ri = cookie; + struct cfxga_screen *scr = ri->ri_hw; + int x, y, cx, cy; + + (*scr->scr_ops.copycols)(ri, row, src, dst, num); + x = dst * ri->ri_font->fontwidth + ri->ri_xorigin; + y = row * ri->ri_font->fontheight + ri->ri_yorigin; + cx = num * ri->ri_font->fontwidth; + cy = ri->ri_font->fontheight; + cfxga_memory_rop(scr->scr_sc, scr, CROP_EXTCOPY, x, y, cx, cy); +} + +void +cfxga_copyrows(void *cookie, int src, int dst, int num) +{ + struct rasops_info *ri = cookie; + struct cfxga_screen *scr = ri->ri_hw; + int x, y, cx, cy; + + (*scr->scr_ops.copyrows)(ri, src, dst, num); + + x = ri->ri_xorigin; + y = dst * ri->ri_font->fontheight + ri->ri_yorigin; + cx = ri->ri_emuwidth; + cy = num * ri->ri_font->fontheight; + cfxga_memory_rop(scr->scr_sc, scr, CROP_EXTCOPY, x, y, cx, cy); +} + +void +cfxga_do_cursor(struct rasops_info *ri) +{ + struct cfxga_screen *scr = ri->ri_hw; + int x, y, cx, cy; + + x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin; + y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin; + cx = ri->ri_font->fontwidth; + cy = ri->ri_font->fontheight; +#if 0 + cfxga_standalone_rop(scr->scr_sc, CROP_SRCXORDST, x, y, cx, cy, 0); +#else + (*scr->scr_do_cursor)(ri); + cfxga_memory_rop(scr->scr_sc, scr, CROP_EXTCOPY, x, y, cx, cy); +#endif +} + +void +cfxga_erasecols(void *cookie, int row, int col, int num, long attr) +{ + struct rasops_info *ri = cookie; + struct cfxga_screen *scr = ri->ri_hw; + int fg, bg, uline; + int x, y, cx, cy; + + (*scr->scr_ops.erasecols)(ri, row, col, num, attr); + + rasops_unpack_attr(attr, &fg, &bg, &uline); + x = col * ri->ri_font->fontwidth + ri->ri_xorigin; + y = row * ri->ri_font->fontheight + ri->ri_yorigin; + cx = num * ri->ri_font->fontwidth; + cy = ri->ri_font->fontheight; + cfxga_standalone_rop(scr->scr_sc, CROP_SOLIDFILL, x, y, cx, cy, + ri->ri_devcmap[bg]); +} + +void +cfxga_eraserows(void *cookie, int row, int num, long attr) +{ + struct rasops_info *ri = cookie; + struct cfxga_screen *scr = ri->ri_hw; + int fg, bg, uline; + int x, y, cx, cy; + + (*scr->scr_ops.eraserows)(ri, row, num, attr); + + rasops_unpack_attr(attr, &fg, &bg, &uline); + x = ri->ri_xorigin; + y = row * ri->ri_font->fontheight + ri->ri_yorigin; + cx = ri->ri_emuwidth; + cy = num * ri->ri_font->fontheight; + cfxga_standalone_rop(scr->scr_sc, CROP_SOLIDFILL, x, y, cx, cy, + ri->ri_devcmap[bg]); +} + +void +cfxga_putchar(void *cookie, int row, int col, u_int uc, long attr) +{ + struct rasops_info *ri = cookie; + struct cfxga_screen *scr = ri->ri_hw; + int x, y, cx, cy; + + (*scr->scr_ops.putchar)(ri, row, col, uc, attr); + + x = col * ri->ri_font->fontwidth + ri->ri_xorigin; + y = row * ri->ri_font->fontheight + ri->ri_yorigin; + cx = ri->ri_font->fontwidth; + cy = ri->ri_font->fontheight; + + if (uc == ' ') { + int fg, bg, uline; + + rasops_unpack_attr(attr, &fg, &bg, &uline); + cfxga_standalone_rop(scr->scr_sc, CROP_SOLIDFILL, x, y, cx, cy, + ri->ri_devcmap[bg]); + } else + cfxga_memory_rop(scr->scr_sc, scr, CROP_EXTCOPY, x, y, cx, cy); +} diff --git a/sys/dev/pcmcia/cfxgareg.h b/sys/dev/pcmcia/cfxgareg.h new file mode 100644 index 00000000000..c925c6a750e --- /dev/null +++ b/sys/dev/pcmcia/cfxgareg.h @@ -0,0 +1,55 @@ +/* $OpenBSD: cfxgareg.h,v 1.1 2006/04/16 20:45:00 miod Exp $ */ + +/* + * Copyright (c) 2005 Matthieu Herrb and 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. + */ + +/* + * (very scarce) registers layout. Actual chip documentation would be immensely + * appreciated. + */ +#define CFREG_RESET 0x0000 /* reset and ID register */ +#define CR_RESET 0x8080 +#define CR_ID_MASK 0x00fc +#define CR_ID 0x001c + +#define CFREG_BLT_CTRL 0x0100 /* control/status */ +#define CC_FIFO_BUSY 0x0010 +#define CC_BLT_BUSY 0x0080 +#define CC_BPP_8 0x0000 +#define CC_BPP_16 0x0180 +#define CFREG_BLT_ROP 0x0102 /* raster op */ +#if 0 +#define CROP_SRCXORDST 0x0606 /* not so right... */ +#endif +#define CROP_SOLIDFILL 0x0c0c +#define CROP_EXTCOPY 0x000c +#define CFREG_BLT_UNK1 0x0104 +#define CFREG_BLT_UNK2 0x0106 +#define CFREG_BLT_SRCLOW 0x0108 +#define CFREG_BLT_SRCHIGH 0x010a +#define CFREG_BLT_STRIDE 0x010c +#define CFREG_BLT_WIDTH 0x0110 +#define CFREG_BLT_HEIGHT 0x0112 +#define CFREG_BLT_SRCCOLOR 0x0118 + +#define CFREG_VIDEO 0x01fc +#define CV_VIDEO_VGA 0x0002 + +#define CFREG_BLT_DATA 0x0400 + +#ifdef _KERNEL +#define CFXGA_MEM_RANGE 0x0800 +#endif diff --git a/sys/dev/pcmcia/files.pcmcia b/sys/dev/pcmcia/files.pcmcia index c2258786138..bad941f812c 100644 --- a/sys/dev/pcmcia/files.pcmcia +++ b/sys/dev/pcmcia/files.pcmcia @@ -1,4 +1,4 @@ -# $OpenBSD: files.pcmcia,v 1.38 2005/03/08 20:00:25 tdeval Exp $ +# $OpenBSD: files.pcmcia,v 1.39 2006/04/16 20:45:00 miod Exp $ # $NetBSD: files.pcmcia,v 1.9 1998/06/21 18:45:41 christos Exp $ # # Config.new file and device description for machine-independent PCMCIA code. @@ -95,3 +95,8 @@ file dev/pcmcia/if_an_pcmcia.c an_pcmcia device gpr attach gpr at pcmcia with gpr file dev/pcmcia/gpr.c gpr needs-flag + +# IODATA CFXGA Compact flash VGA card +device cfxga: wsemuldisplaydev, rasops16 +attach cfxga at pcmcia with cfxga +file dev/pcmcia/cfxga.c cfxga |