void tcx_prom(void *v) { struct tcx_softc *sc = v; extern struct consdev consdev_prom; if (sc->sc_sunfb.sf_depth != 8) { /* * Select 8-bit mode. */ tcx_reset(sc, 8); /* * Go back to prom output for the last few messages, so they * will be displayed correctly. */ cn_tab = &consdev_prom; } }
static int tcx_probe(struct platform_device *op) { struct device_node *dp = op->dev.of_node; struct fb_info *info; struct tcx_par *par; int linebytes, i, err; info = framebuffer_alloc(sizeof(struct tcx_par), &op->dev); err = -ENOMEM; if (!info) goto out_err; par = info->par; spin_lock_init(&par->lock); par->lowdepth = (of_find_property(dp, "tcx-8-bit", NULL) != NULL); sbusfb_fill_var(&info->var, dp, 8); info->var.red.length = 8; info->var.green.length = 8; info->var.blue.length = 8; linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); par->tec = of_ioremap(&op->resource[7], 0, sizeof(struct tcx_tec), "tcx tec"); par->thc = of_ioremap(&op->resource[9], 0, sizeof(struct tcx_thc), "tcx thc"); par->bt = of_ioremap(&op->resource[8], 0, sizeof(struct bt_regs), "tcx dac"); info->screen_base = of_ioremap(&op->resource[0], 0, info->fix.smem_len, "tcx ram"); if (!par->tec || !par->thc || !par->bt || !info->screen_base) goto out_unmap_regs; memcpy(&par->mmap_map, &__tcx_mmap_map, sizeof(par->mmap_map)); if (!par->lowdepth) { par->cplane = of_ioremap(&op->resource[4], 0, info->fix.smem_len * sizeof(u32), "tcx cplane"); if (!par->cplane) goto out_unmap_regs; } else { par->mmap_map[1].size = SBUS_MMAP_EMPTY; par->mmap_map[4].size = SBUS_MMAP_EMPTY; par->mmap_map[5].size = SBUS_MMAP_EMPTY; par->mmap_map[6].size = SBUS_MMAP_EMPTY; } info->fix.smem_start = op->resource[0].start; par->which_io = op->resource[0].flags & IORESOURCE_BITS; for (i = 0; i < TCX_MMAP_ENTRIES; i++) { int j; switch (i) { case 10: j = 12; break; case 11: case 12: j = i - 1; break; default: j = i; break; } par->mmap_map[i].poff = op->resource[j].start; } info->flags = FBINFO_DEFAULT; info->fbops = &tcx_ops; /* Initialize brooktree DAC. */ sbus_writel(0x04 << 24, &par->bt->addr); /* color planes */ sbus_writel(0xff << 24, &par->bt->control); sbus_writel(0x05 << 24, &par->bt->addr); sbus_writel(0x00 << 24, &par->bt->control); sbus_writel(0x06 << 24, &par->bt->addr); /* overlay plane */ sbus_writel(0x73 << 24, &par->bt->control); sbus_writel(0x07 << 24, &par->bt->addr); sbus_writel(0x00 << 24, &par->bt->control); tcx_reset(info); tcx_blank(FB_BLANK_UNBLANK, info); if (fb_alloc_cmap(&info->cmap, 256, 0)) goto out_unmap_regs; fb_set_cmap(&info->cmap, info); tcx_init_fix(info, linebytes); err = register_framebuffer(info); if (err < 0) goto out_dealloc_cmap; dev_set_drvdata(&op->dev, info); printk(KERN_INFO "%s: TCX at %lx:%lx, %s\n", dp->full_name, par->which_io, info->fix.smem_start, par->lowdepth ? "8-bit only" : "24-bit depth"); return 0; out_dealloc_cmap: fb_dealloc_cmap(&info->cmap); out_unmap_regs: tcx_unmap_regs(op, info, par); framebuffer_release(info); out_err: return err; }
static int tcx_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { tcx_reset(info); return 0; }
int tcx_ioctl(void *dev, u_long cmd, caddr_t data, int flags, struct proc *p) { struct tcx_softc *sc = dev; struct wsdisplay_cmap *cm; struct wsdisplay_fbinfo *wdf; int error; /* * Note that, although the emulation (text) mode is running in 8-bit * mode, if the frame buffer is able to run in 24-bit mode, it will * be advertized as such. */ switch (cmd) { case WSDISPLAYIO_GTYPE: *(u_int *)data = WSDISPLAY_TYPE_SUNTCX; break; case WSDISPLAYIO_GINFO: wdf = (struct wsdisplay_fbinfo *)data; wdf->height = sc->sc_sunfb.sf_height; wdf->width = sc->sc_sunfb.sf_width; wdf->depth = sc->sc_sunfb.sf_depth; wdf->cmsize = sc->sc_cplane == 0 ? 256 : 0; break; case WSDISPLAYIO_GETSUPPORTEDDEPTH: if (sc->sc_cplane != 0) *(u_int *)data = WSDISPLAYIO_DEPTH_24_32; else return (-1); break; case WSDISPLAYIO_LINEBYTES: if (sc->sc_cplane == 0) *(u_int *)data = sc->sc_sunfb.sf_linebytes; else *(u_int *)data = sc->sc_sunfb.sf_linebytes * 4; break; case WSDISPLAYIO_GETCMAP: if (sc->sc_cplane == 0) { cm = (struct wsdisplay_cmap *)data; error = bt_getcmap(&sc->sc_cmap, cm); if (error) return (error); } break; case WSDISPLAYIO_PUTCMAP: if (sc->sc_cplane == 0) { cm = (struct wsdisplay_cmap *)data; error = bt_putcmap(&sc->sc_cmap, cm); if (error) return (error); tcx_loadcmap_deferred(sc, cm->index, cm->count); } break; case WSDISPLAYIO_SMODE: if (*(int *)data == WSDISPLAYIO_MODE_EMUL) { /* Back from X11 to text mode */ tcx_reset(sc, 8); } else { /* Starting X11, try to switch to 24 bit mode */ if (sc->sc_cplane != 0) tcx_reset(sc, 32); } break; case WSDISPLAYIO_SVIDEO: case WSDISPLAYIO_GVIDEO: break; default: return (-1); /* not supported yet */ } return (0); }
void tcxattach(struct device *parent, struct device *self, void *args) { struct tcx_softc *sc = (struct tcx_softc *)self; struct confargs *ca = args; int node, pri; int isconsole = 0; char *nam = NULL; vaddr_t thc_offset; pri = ca->ca_ra.ra_intr[0].int_pri; printf(" pri %d: ", pri); node = ca->ca_ra.ra_node; isconsole = node == fbnode; if (ca->ca_ra.ra_nreg < TCX_NREG) { printf("expected %d registers, got %d\n", TCX_NREG, ca->ca_ra.ra_nreg); return; } nam = getpropstring(node, "model"); if (*nam != '\0') printf("%s, ", nam); /* * Copy the register address spaces needed for mmap operation. */ sc->sc_phys[0] = ca->ca_ra.ra_reg[TCX_REG_DFB8]; sc->sc_phys[1] = ca->ca_ra.ra_reg[TCX_REG_DFB24]; /* * Can't trust the PROM range len here, it is only 4 bytes on the * 8-bit model. Not that it matters much anyway since we map in * pages. */ sc->sc_bt = (volatile struct bt_regs *) mapiodev(&ca->ca_ra.ra_reg[TCX_REG_CMAP], 0, sizeof *sc->sc_bt); /* * For some reason S24 PROM sets up TEC and THC ranges at the * right addresses (701000 and 301000), while 8 bit TCX doesn't * (and uses 70000 and 30000) - be sure to only compensate on 8 bit * models. */ if (((vaddr_t)ca->ca_ra.ra_reg[TCX_REG_THC].rr_paddr & 0x1000) != 0) thc_offset = 0; else thc_offset = 0x1000; sc->sc_thc = (volatile struct tcx_thc *) mapiodev(&ca->ca_ra.ra_reg[TCX_REG_THC], thc_offset, sizeof *sc->sc_thc); /* * Find out frame buffer geometry, so that we know how much * memory to map. */ fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, ca->ca_bustype); sc->sc_dfb8 = mapiodev(&ca->ca_ra.ra_reg[TCX_REG_DFB8], 0, round_page(sc->sc_sunfb.sf_fbsize)); /* * If the frame buffer advertizes itself as the 8 bit model, or * if the PROM ranges are too small, limit ourselves to 8 bit * operations. * * Further code needing to know which capabilities the frame buffer * has will rely on sc_cplane being non-zero if 24 bit operation * is possible. */ if (!node_has_property(node, "tcx-8-bit") && ca->ca_ra.ra_reg[TCX_REG_RDFB32].rr_len >= sc->sc_sunfb.sf_fbsize * 4) { sc->sc_cplane = (paddr_t)ca->ca_ra.ra_reg[TCX_REG_RDFB32].rr_paddr; } printf("%dx%dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height, sc->sc_cplane == 0 ? 8 : 24); /* * Set up mappings for the acceleration code. This may fail. */ tcx_accel_init(sc, ca); /* reset cursor & frame buffer controls */ tcx_reset(sc, 8); /* enable video */ tcx_burner(sc, 1, 0); sc->sc_sunfb.sf_ro.ri_hw = sc; sc->sc_sunfb.sf_ro.ri_bits = (void *)sc->sc_dfb8; fbwscons_init(&sc->sc_sunfb, isconsole); fbwscons_setcolormap(&sc->sc_sunfb, tcx_setcolor); /* * Now plug accelerated console routines, if possible. */ tcx_accel_plug(sc, ca); sc->sc_ih.ih_fun = tcx_intr; sc->sc_ih.ih_arg = sc; intr_establish(pri, &sc->sc_ih, IPL_FB, self->dv_xname); if (isconsole) { fbwscons_console_init(&sc->sc_sunfb, -1); shutdownhook_establish(tcx_prom, sc); } fbwscons_attach(&sc->sc_sunfb, &tcx_accessops, isconsole); }
void tcx_init(target_phys_addr_t addr, int vram_size, int width, int height, int depth) { TCXState *s; int io_memory, dummy_memory; ram_addr_t vram_offset; int size; uint8_t *vram_base; vram_offset = qemu_ram_alloc(vram_size * (1 + 4 + 4)); vram_base = qemu_get_ram_ptr(vram_offset); s = qemu_mallocz(sizeof(TCXState)); s->addr = addr; s->vram_offset = vram_offset; s->width = width; s->height = height; s->depth = depth; // 8-bit plane s->vram = vram_base; size = vram_size; cpu_register_physical_memory(addr + 0x00800000ULL, size, vram_offset); vram_offset += size; vram_base += size; io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s); cpu_register_physical_memory(addr + 0x00200000ULL, TCX_DAC_NREGS, io_memory); dummy_memory = cpu_register_io_memory(0, tcx_dummy_read, tcx_dummy_write, s); cpu_register_physical_memory(addr + 0x00700000ULL, TCX_TEC_NREGS, dummy_memory); if (depth == 24) { // 24-bit plane size = vram_size * 4; s->vram24 = (uint32_t *)vram_base; s->vram24_offset = vram_offset; cpu_register_physical_memory(addr + 0x02000000ULL, size, vram_offset); vram_offset += size; vram_base += size; // Control plane size = vram_size * 4; s->cplane = (uint32_t *)vram_base; s->cplane_offset = vram_offset; cpu_register_physical_memory(addr + 0x0a000000ULL, size, vram_offset); s->ds = graphic_console_init(tcx24_update_display, tcx24_invalidate_display, tcx24_screen_dump, NULL, s); } else { cpu_register_physical_memory(addr + 0x00300000ULL, TCX_THC_NREGS_8, dummy_memory); s->ds = graphic_console_init(tcx_update_display, tcx_invalidate_display, tcx_screen_dump, NULL, s); } // NetBSD writes here even with 8-bit display cpu_register_physical_memory(addr + 0x00301000ULL, TCX_THC_NREGS_24, dummy_memory); register_savevm("tcx", addr, 4, tcx_save, tcx_load, s); qemu_register_reset(tcx_reset, s); tcx_reset(s); qemu_console_resize(s->ds, width, height); }
static int __devinit tcx_init_one(struct of_device *op) { struct device_node *dp = op->node; struct all_info *all; int linebytes, i, err; all = kzalloc(sizeof(*all), GFP_KERNEL); if (!all) return -ENOMEM; spin_lock_init(&all->par.lock); all->par.lowdepth = (of_find_property(dp, "tcx-8-bit", NULL) != NULL); sbusfb_fill_var(&all->info.var, dp->node, 8); all->info.var.red.length = 8; all->info.var.green.length = 8; all->info.var.blue.length = 8; linebytes = of_getintprop_default(dp, "linebytes", all->info.var.xres); all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); all->par.tec = of_ioremap(&op->resource[7], 0, sizeof(struct tcx_tec), "tcx tec"); all->par.thc = of_ioremap(&op->resource[9], 0, sizeof(struct tcx_thc), "tcx thc"); all->par.bt = of_ioremap(&op->resource[8], 0, sizeof(struct bt_regs), "tcx dac"); all->info.screen_base = of_ioremap(&op->resource[0], 0, all->par.fbsize, "tcx ram"); if (!all->par.tec || !all->par.thc || !all->par.bt || !all->info.screen_base) { tcx_unmap_regs(all); kfree(all); return -ENOMEM; } memcpy(&all->par.mmap_map, &__tcx_mmap_map, sizeof(all->par.mmap_map)); if (!all->par.lowdepth) { all->par.cplane = of_ioremap(&op->resource[4], 0, all->par.fbsize * sizeof(u32), "tcx cplane"); if (!all->par.cplane) { tcx_unmap_regs(all); kfree(all); return -ENOMEM; } } else { all->par.mmap_map[1].size = SBUS_MMAP_EMPTY; all->par.mmap_map[4].size = SBUS_MMAP_EMPTY; all->par.mmap_map[5].size = SBUS_MMAP_EMPTY; all->par.mmap_map[6].size = SBUS_MMAP_EMPTY; } all->par.physbase = 0; all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; for (i = 0; i < TCX_MMAP_ENTRIES; i++) { int j; switch (i) { case 10: j = 12; break; case 11: case 12: j = i - 1; break; default: j = i; break; }; all->par.mmap_map[i].poff = op->resource[j].start; } all->info.flags = FBINFO_DEFAULT; all->info.fbops = &tcx_ops; all->info.par = &all->par; /* Initialize brooktree DAC. */ sbus_writel(0x04 << 24, &all->par.bt->addr); /* color planes */ sbus_writel(0xff << 24, &all->par.bt->control); sbus_writel(0x05 << 24, &all->par.bt->addr); sbus_writel(0x00 << 24, &all->par.bt->control); sbus_writel(0x06 << 24, &all->par.bt->addr); /* overlay plane */ sbus_writel(0x73 << 24, &all->par.bt->control); sbus_writel(0x07 << 24, &all->par.bt->addr); sbus_writel(0x00 << 24, &all->par.bt->control); tcx_reset(&all->info); tcx_blank(FB_BLANK_UNBLANK, &all->info); if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { tcx_unmap_regs(all); kfree(all); return -ENOMEM; } fb_set_cmap(&all->info.cmap, &all->info); tcx_init_fix(&all->info, linebytes); err = register_framebuffer(&all->info); if (err < 0) { fb_dealloc_cmap(&all->info.cmap); tcx_unmap_regs(all); kfree(all); return err; } dev_set_drvdata(&op->dev, all); printk("%s: TCX at %lx:%lx, %s\n", dp->full_name, all->par.which_io, op->resource[0].start, all->par.lowdepth ? "8-bit only" : "24-bit depth"); return 0; }
__initfunc(char *tcxfb_init(struct fb_info_sbusfb *fb)) { struct fb_fix_screeninfo *fix = &fb->fix; struct display *disp = &fb->disp; struct fbtype *type = &fb->type; unsigned long phys = fb->sbdp->reg_addrs[0].phys_addr; int lowdepth, i, j; #ifndef FBCON_HAS_CFB8 return NULL; #endif lowdepth = prom_getbool (fb->prom_node, "tcx-8-bit"); if (lowdepth) { strcpy(fb->info.modename, "TCX8"); strcpy(fix->id, "TCX8"); } else { strcpy(fb->info.modename, "TCX24"); strcpy(fix->id, "TCX24"); } fix->line_length = fb->var.xres_virtual; disp->scrollmode = SCROLL_YREDRAW; if (!disp->screen_base) disp->screen_base = (char *)sparc_alloc_io(phys, 0, type->fb_size, "tcx_ram", fb->iospace, 0); disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin; fb->s.tcx.tec = (struct tcx_tec *)sparc_alloc_io(fb->sbdp->reg_addrs[7].phys_addr, 0, sizeof(struct tcx_tec), "tcx_tec", fb->iospace, 0); fb->s.tcx.thc = (struct tcx_thc *)sparc_alloc_io(fb->sbdp->reg_addrs[9].phys_addr, 0, sizeof(struct tcx_thc), "tcx_thc", fb->iospace, 0); fb->s.tcx.bt = (struct bt_regs *)sparc_alloc_io(fb->sbdp->reg_addrs[8].phys_addr, 0, sizeof(struct bt_regs), "tcx_dac", fb->iospace, 0); if (!lowdepth) { fb->s.tcx.cplane = (u32 *)sparc_alloc_io(fb->sbdp->reg_addrs[4].phys_addr, 0, type->fb_size*4, "tcx_cplane", fb->iospace, 0); type->fb_depth = 24; fb->switch_from_graph = tcx_switch_from_graph; } else { /* As there can be one tcx in a machine only, we can write directly into tcx_mmap_map */ tcx_mmap_map[1].size = SBUS_MMAP_EMPTY; tcx_mmap_map[4].size = SBUS_MMAP_EMPTY; tcx_mmap_map[5].size = SBUS_MMAP_EMPTY; tcx_mmap_map[6].size = SBUS_MMAP_EMPTY; } fb->dispsw = fbcon_cfb8; fb->margins = tcx_margins; fb->loadcmap = tcx_loadcmap; if (prom_getbool (fb->prom_node, "hw-cursor")) { fb->setcursor = tcx_setcursor; fb->setcursormap = tcx_setcursormap; fb->setcurshape = tcx_setcurshape; } fb->restore_palette = tcx_restore_palette; fb->blank = tcx_blank; fb->unblank = tcx_unblank; fb->reset = tcx_reset; fb->physbase = 0; for (i = 0; i < 13; i++) { /* tcx_mmap_map has to be sorted by voff, while order of phys registers from PROM differs a little bit. Here is the correction */ switch (i) { case 10: j = 12; break; case 11: case 12: j = i - 1; break; default: j = i; break; } tcx_mmap_map[i].poff = fb->sbdp->reg_addrs[j].phys_addr; } fb->mmap_map = tcx_mmap_map; /* Initialize Brooktree DAC */ fb->s.tcx.bt->addr = 0x04 << 24; /* color planes */ fb->s.tcx.bt->control = 0xff << 24; fb->s.tcx.bt->addr = 0x05 << 24; fb->s.tcx.bt->control = 0x00 << 24; fb->s.tcx.bt->addr = 0x06 << 24; /* overlay plane */ fb->s.tcx.bt->control = 0x73 << 24; fb->s.tcx.bt->addr = 0x07 << 24; fb->s.tcx.bt->control = 0x00 << 24; sprintf(idstring, "tcx at %x.%08lx Rev %d.%d %s", fb->iospace, phys, (fb->s.tcx.thc->thc_rev >> TCX_THC_REV_REV_SHIFT) & TCX_THC_REV_REV_MASK, (fb->s.tcx.thc->thc_rev >> TCX_THC_REV_MINREV_SHIFT) & TCX_THC_REV_MINREV_MASK, lowdepth ? "8-bit only" : "24-bit depth"); tcx_reset(fb); return idstring; }