#include #include #include #include #include #include #include #include #include #include #include #include #include #define FBC_READ(sc, r) \ bus_space_read_4((sc)->sc_bt, (sc)->sc_fbc_h, (r)) #define FBC_WRITE(sc, r, v) \ bus_space_write_4((sc)->sc_bt, (sc)->sc_fbc_h, (r), (v)) #define DAC_READ(sc, r) \ bus_space_read_4((sc)->sc_bt, (sc)->sc_dac_h, (r)) #define DAC_WRITE(sc, r, v) \ bus_space_write_4((sc)->sc_bt, (sc)->sc_dac_h, (r), (v)) struct creator_softc { device_t sc_dev; int sc_type; int sc_dac; struct resource * sc_reg[FFB_NREG]; int sc_rid[FFB_NREG]; int sc_nreg; bus_space_tag_t sc_bt; bus_space_handle_t sc_dac_h; bus_space_handle_t sc_fbc_h; bus_space_handle_t sc_pixel_h; int sc_fifo_cache; int sc_bg_cache; int sc_fg_cache; int sc_height; int sc_width; int sc_fontheight; int sc_fontwidth; uint8_t * sc_fontdata; }; static int creator_attach(device_t dev); static int creator_detach(device_t dev); static int creator_probe(device_t dev); static void creator_ras_init(struct creator_softc *sc); static void creator_ras_fifo_wait(struct creator_softc *sc, int n); static void creator_ras_wait(struct creator_softc *); static void creator_ras_fill(struct creator_softc *); static void creator_ras_setbg(struct creator_softc *, int32_t bg); static void creator_ras_setfg(struct creator_softc *, int32_t fg); static void creator_unblank(struct creator_softc *); static void creator_putc(struct creator_softc *sc, int x, int y, int c); static device_method_t creator_methods[] = { DEVMETHOD(device_probe, creator_probe), DEVMETHOD(device_attach, creator_attach), DEVMETHOD(device_detach, creator_detach), { 0, 0 } }; static driver_t creator_driver = { "creator", creator_methods, sizeof(struct creator_softc), }; static devclass_t creator_devclass; DRIVER_MODULE(creator, nexus, creator_driver, creator_devclass, 0, 0); static int creator_probe(device_t dev) { const char *name; phandle_t node; int type; name = nexus_get_name(dev); node = nexus_get_node(dev); if (strcmp(name, "SUNW,ffb") == 0) { if (OF_getprop(node, "board_type", &type, sizeof(type)) == -1) return (ENXIO); switch (type & 7) { case 0x0: device_set_desc(dev, "Creator"); break; case 0x3: device_set_desc(dev, "Creator3d"); break; default: return (ENXIO); } } else if (strcmp(name, "SUNW,afb") == 0) device_set_desc(dev, "Elite3D"); else return (ENXIO); return (0); } static int creator_attach(device_t dev) { struct creator_softc *sc; struct upa_regs *reg; bus_addr_t phys; bus_size_t size; phandle_t node; char model[32]; int height; int width; int type; int i; node = nexus_get_node(dev); if (OF_getprop(node, "model", model, sizeof(model)) == -1 || OF_getprop(node, "board_type", &type, sizeof(type)) == -1 || OF_getprop(node, "height", &height, sizeof(height)) == -1 || OF_getprop(node, "width", &width, sizeof(width)) == -1) return (ENXIO); sc = device_get_softc(dev); sc->sc_dev = dev; sc->sc_type = type; sc->sc_height = height; sc->sc_width = width; sc->sc_nreg = nexus_get_nreg(dev); sc->sc_fontheight = 22; sc->sc_fontwidth = 12; sc->sc_fontdata = gallant12x22_data; reg = nexus_get_reg(dev); for (i = 0; i < sc->sc_nreg; i++) { phys = UPA_REG_PHYS(reg + i); size = UPA_REG_SIZE(reg + i); sc->sc_reg[i] = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->sc_rid[i], phys, phys + size - 1, 1, RF_ACTIVE); if (sc->sc_reg[i] == NULL) goto error; } sc->sc_bt = rman_get_bustag(sc->sc_reg[0]); sc->sc_dac_h = rman_get_bushandle(sc->sc_reg[FFB_REG_DAC]); sc->sc_fbc_h = rman_get_bushandle(sc->sc_reg[FFB_REG_FBC]); sc->sc_pixel_h = rman_get_bushandle(sc->sc_reg[FFB_REG_DFB24]); DAC_WRITE(sc, FFB_DAC_TYPE, 0x8000); sc->sc_dac = (DAC_READ(sc, FFB_DAC_VALUE) >> 0x1c); creator_ras_init(sc); creator_unblank(sc); creator_ras_fill(sc); creator_ras_setfg(sc, 0xffffff); creator_ras_fifo_wait(sc, 4); FBC_WRITE(sc, FFB_FBC_BY, 0); FBC_WRITE(sc, FFB_FBC_BX, 0); FBC_WRITE(sc, FFB_FBC_BH, sc->sc_height); FBC_WRITE(sc, FFB_FBC_BW, sc->sc_width); creator_ras_setbg(sc, 0xffffff); creator_ras_setfg(sc, 0x0); creator_putc(sc, 0, 0, 'a'); creator_putc(sc, 0, 33, 'a'); creator_putc(sc, 79, 0, 'a'); creator_putc(sc, 79, 33, 'a'); #if 0 for (y = 0; y < 34; y++) { for (x = 0; x < 80; x++) { creator_ras_fifo_wait(sc, 2 + 24); FBC_WRITE(sc, FFB_FBC_FONTXY, ((y * 24) << 16) | (x * 14)); FBC_WRITE(sc, FFB_FBC_FONTW, 14); for (i = 0; i < 24; i++) FBC_WRITE(sc, FFB_FBC_FONT, y & 1 ? (x & 1) ? 0xffff0000 : 0x0 : 0x0); } } #endif device_printf(dev, "model %s type %d dac %d\n", model, sc->sc_type, sc->sc_dac); device_printf(dev, "height %d width %d\n", sc->sc_height, sc->sc_width); return (0); error: creator_detach(dev); return (ENXIO); } static int creator_detach(device_t dev) { struct creator_softc *sc; int i; sc = device_get_softc(dev); for (i = 0; i < sc->sc_nreg; i++) { if (sc->sc_reg[i] != NULL) bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid[i], sc->sc_reg[i]); } return (0); } static void creator_ras_init(struct creator_softc *sc) { creator_ras_fifo_wait(sc, 7); FBC_WRITE(sc, FFB_FBC_PPC, FBC_PPC_VCE_DIS | FBC_PPC_TBE_OPAQUE | FBC_PPC_APE_DIS | FBC_PPC_CS_CONST); FBC_WRITE(sc, FFB_FBC_FBC, FFB_FBC_WB_A | FFB_FBC_RB_A | FFB_FBC_SB_BOTH | FFB_FBC_XE_OFF | FFB_FBC_RGBE_MASK); FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW); FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE); FBC_WRITE(sc, FFB_FBC_PMASK, 0xffffff); FBC_WRITE(sc, FFB_FBC_FONTINC, 0x10000); sc->sc_fg_cache = 0; FBC_WRITE(sc, FFB_FBC_FG, sc->sc_fg_cache); creator_ras_wait(sc); } static void creator_ras_fifo_wait(struct creator_softc *sc, int n) { int32_t cache = sc->sc_fifo_cache; if (cache < n) { do { cache = FBC_READ(sc, FFB_FBC_UCSR); cache = (cache & FBC_UCSR_FIFO_MASK) - 8; } while (cache < n); } sc->sc_fifo_cache = cache - n; } static void creator_ras_wait(struct creator_softc *sc) { u_int32_t ucsr, r; while (1) { ucsr = FBC_READ(sc, FFB_FBC_UCSR); if ((ucsr & (FBC_UCSR_FB_BUSY|FBC_UCSR_RP_BUSY)) == 0) break; r = ucsr & (FBC_UCSR_READ_ERR | FBC_UCSR_FIFO_OVFL); if (r != 0) FBC_WRITE(sc, FFB_FBC_UCSR, r); } } static void creator_ras_fill(struct creator_softc *sc) { creator_ras_fifo_wait(sc, 2); FBC_WRITE(sc, FFB_FBC_ROP, FBC_ROP_NEW); FBC_WRITE(sc, FFB_FBC_DRAWOP, FBC_DRAWOP_RECTANGLE); creator_ras_wait(sc); } static void creator_ras_setbg(struct creator_softc *sc, int32_t bg) { creator_ras_fifo_wait(sc, 1); if (bg == sc->sc_bg_cache) return; sc->sc_bg_cache = bg; FBC_WRITE(sc, FFB_FBC_BG, bg); creator_ras_wait(sc); } static void creator_ras_setfg(struct creator_softc *sc, int32_t fg) { creator_ras_fifo_wait(sc, 1); if (fg == sc->sc_fg_cache) return; sc->sc_fg_cache = fg; FBC_WRITE(sc, FFB_FBC_FG, fg); creator_ras_wait(sc); } static void creator_unblank(struct creator_softc *sc) { uint32_t v; DAC_WRITE(sc, FFB_DAC_TYPE, 0x6000); v = DAC_READ(sc, FFB_DAC_VALUE); DAC_WRITE(sc, FFB_DAC_TYPE, 0x6000); DAC_WRITE(sc, FFB_DAC_VALUE, v | 0x1); } static void creator_putc(struct creator_softc *sc, int x, int y, int c) { uint16_t *p; int i; y *= sc->sc_fontheight; x *= sc->sc_fontwidth; p = (uint16_t *)(sc->sc_fontdata + ((c - ' ') * sc->sc_fontheight * 2)); creator_ras_fifo_wait(sc, 2 + sc->sc_fontheight); FBC_WRITE(sc, FFB_FBC_FONTXY, (y << 16) | x); FBC_WRITE(sc, FFB_FBC_FONTW, sc->sc_fontwidth); for (i = 0; i < sc->sc_fontheight; i++) FBC_WRITE(sc, FFB_FBC_FONT, *p++ << 16); }