1 1.93 andvar /* $NetBSD: tga.c,v 1.93 2024/02/09 22:08:36 andvar Exp $ */ 2 1.1 drochner 3 1.1 drochner /* 4 1.1 drochner * Copyright (c) 1995, 1996 Carnegie-Mellon University. 5 1.1 drochner * All rights reserved. 6 1.1 drochner * 7 1.1 drochner * Author: Chris G. Demetriou 8 1.60 perry * 9 1.1 drochner * Permission to use, copy, modify and distribute this software and 10 1.1 drochner * its documentation is hereby granted, provided that both the copyright 11 1.1 drochner * notice and this permission notice appear in all copies of the 12 1.1 drochner * software, derivative works or modified versions, and any portions 13 1.1 drochner * thereof, and that both notices appear in supporting documentation. 14 1.60 perry * 15 1.60 perry * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 1.60 perry * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 17 1.1 drochner * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 1.60 perry * 19 1.1 drochner * Carnegie Mellon requests users of this software to return to 20 1.1 drochner * 21 1.1 drochner * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 22 1.1 drochner * School of Computer Science 23 1.1 drochner * Carnegie Mellon University 24 1.1 drochner * Pittsburgh PA 15213-3890 25 1.1 drochner * 26 1.1 drochner * any improvements or extensions that they make and grant Carnegie the 27 1.1 drochner * rights to redistribute these changes. 28 1.1 drochner */ 29 1.37 lukem 30 1.37 lukem #include <sys/cdefs.h> 31 1.93 andvar __KERNEL_RCSID(0, "$NetBSD: tga.c,v 1.93 2024/02/09 22:08:36 andvar Exp $"); 32 1.1 drochner 33 1.1 drochner #include <sys/param.h> 34 1.1 drochner #include <sys/systm.h> 35 1.1 drochner #include <sys/kernel.h> 36 1.1 drochner #include <sys/device.h> 37 1.1 drochner #include <sys/conf.h> 38 1.1 drochner #include <sys/malloc.h> 39 1.1 drochner #include <sys/buf.h> 40 1.1 drochner #include <sys/ioctl.h> 41 1.8 thorpej 42 1.67 ad #include <sys/bus.h> 43 1.67 ad #include <sys/intr.h> 44 1.1 drochner 45 1.1 drochner #include <dev/pci/pcireg.h> 46 1.1 drochner #include <dev/pci/pcivar.h> 47 1.1 drochner #include <dev/pci/pcidevs.h> 48 1.69 ahoka #include <dev/pci/pciio.h> 49 1.1 drochner #include <dev/pci/tgareg.h> 50 1.1 drochner #include <dev/pci/tgavar.h> 51 1.1 drochner #include <dev/ic/bt485reg.h> 52 1.17 elric #include <dev/ic/bt485var.h> 53 1.22 nathanw #include <dev/ic/bt463reg.h> 54 1.22 nathanw #include <dev/ic/bt463var.h> 55 1.38 elric #include <dev/ic/ibm561var.h> 56 1.1 drochner 57 1.1 drochner #include <dev/wscons/wsconsio.h> 58 1.1 drochner #include <dev/wscons/wscons_raster.h> 59 1.23 nathanw #include <dev/rasops/rasops.h> 60 1.23 nathanw #include <dev/wsfont/wsfont.h> 61 1.81 cegger #include <dev/pci/wsdisplay_pci.h> 62 1.81 cegger 63 1.90 tsutsui static int tgamatch(device_t, cfdata_t, void *); 64 1.90 tsutsui static void tgaattach(device_t, device_t, void *); 65 1.1 drochner 66 1.76 tsutsui CFATTACH_DECL_NEW(tga, sizeof(struct tga_softc), 67 1.49 thorpej tgamatch, tgaattach, NULL, NULL); 68 1.1 drochner 69 1.59 perry static void tga_init(bus_space_tag_t memt, pci_chipset_tag_t pc, 70 1.77 tsutsui pcitag_t tag, struct tga_devconfig *dc); 71 1.1 drochner 72 1.59 perry static int tga_matchcommon(bus_space_tag_t, pci_chipset_tag_t, pcitag_t); 73 1.59 perry static void tga_mapaddrs(bus_space_tag_t memt, pci_chipset_tag_t pc, 74 1.77 tsutsui pcitag_t, bus_size_t *pcisize, struct tga_devconfig *dc); 75 1.90 tsutsui static unsigned int tga_getdotclock(struct tga_devconfig *dc); 76 1.1 drochner 77 1.90 tsutsui static int tga_ioctl(void *, void *, u_long, void *, int, struct lwp *); 78 1.90 tsutsui static paddr_t tga_mmap(void *, void *, off_t, int); 79 1.59 perry static void tga_copyrows(void *, int, int, int); 80 1.59 perry static void tga_copycols(void *, int, int, int, int); 81 1.59 perry static int tga_alloc_screen(void *, const struct wsscreen_descr *, 82 1.77 tsutsui void **, int *, int *, long *); 83 1.59 perry static void tga_free_screen(void *, void *); 84 1.59 perry static int tga_show_screen(void *, void *, int, 85 1.77 tsutsui void (*) (void *, int, int), void *); 86 1.59 perry static int tga_rop(struct rasops_info *, int, int, int, int, int, 87 1.77 tsutsui struct rasops_info *, int, int); 88 1.59 perry static int tga_rop_vtov(struct rasops_info *, int, int, int, int, 89 1.77 tsutsui int, struct rasops_info *, int, int); 90 1.77 tsutsui static void tga_putchar(void *c, int row, int col, u_int uc, long attr); 91 1.59 perry static void tga_eraserows(void *, int, int, long); 92 1.77 tsutsui static void tga_erasecols(void *, int, int, int, long); 93 1.90 tsutsui static void tga2_init(struct tga_devconfig *); 94 1.17 elric 95 1.74 cegger static void tga_config_interrupts(device_t); 96 1.22 nathanw 97 1.17 elric /* RAMDAC interface functions */ 98 1.77 tsutsui static int tga_sched_update(void *, void (*)(void *)); 99 1.77 tsutsui static void tga_ramdac_wr(void *, u_int, uint8_t); 100 1.77 tsutsui static uint8_t tga_ramdac_rd(void *, u_int); 101 1.77 tsutsui static void tga_bt463_wr(void *, u_int, uint8_t); 102 1.77 tsutsui static uint8_t tga_bt463_rd(void *, u_int); 103 1.77 tsutsui static void tga2_ramdac_wr(void *, u_int, uint8_t); 104 1.77 tsutsui static uint8_t tga2_ramdac_rd(void *, u_int); 105 1.17 elric 106 1.17 elric /* Interrupt handler */ 107 1.77 tsutsui static int tga_intr(void *); 108 1.77 tsutsui 109 1.77 tsutsui struct tga_devconfig tga_console_dc; 110 1.14 ross 111 1.23 nathanw /* The NULL entries will get filled in by rasops_init(). 112 1.23 nathanw * XXX and the non-NULL ones will be overwritten; reset after calling it. 113 1.23 nathanw */ 114 1.1 drochner struct wsdisplay_emulops tga_emulops = { 115 1.91 tsutsui .cursor = NULL, 116 1.91 tsutsui .mapchar = NULL, 117 1.91 tsutsui .putchar = tga_putchar, 118 1.91 tsutsui .copycols = tga_copycols, 119 1.91 tsutsui .erasecols = tga_erasecols, 120 1.91 tsutsui .copyrows = tga_copyrows, 121 1.91 tsutsui .eraserows = tga_eraserows, 122 1.91 tsutsui .allocattr = NULL, 123 1.64 cube NULL, 124 1.1 drochner }; 125 1.1 drochner 126 1.1 drochner struct wsscreen_descr tga_stdscreen = { 127 1.91 tsutsui .name = "std", 128 1.91 tsutsui .ncols = 0, 129 1.91 tsutsui .nrows = 0, /* will be filled in -- XXX shouldn't, it's global */ 130 1.91 tsutsui .textops = &tga_emulops, 131 1.91 tsutsui .fontwidth = 0, 132 1.91 tsutsui .fontheight = 0, 133 1.91 tsutsui .capabilities = WSSCREEN_REVERSE, 134 1.91 tsutsui .modecookie = NULL, 135 1.1 drochner }; 136 1.1 drochner 137 1.1 drochner const struct wsscreen_descr *_tga_scrlist[] = { 138 1.1 drochner &tga_stdscreen, 139 1.1 drochner /* XXX other formats, graphics screen? */ 140 1.1 drochner }; 141 1.1 drochner 142 1.1 drochner struct wsscreen_list tga_screenlist = { 143 1.1 drochner sizeof(_tga_scrlist) / sizeof(struct wsscreen_descr *), _tga_scrlist 144 1.1 drochner }; 145 1.1 drochner 146 1.1 drochner struct wsdisplay_accessops tga_accessops = { 147 1.91 tsutsui .ioctl = tga_ioctl, 148 1.91 tsutsui .mmap = tga_mmap, 149 1.91 tsutsui .alloc_screen = tga_alloc_screen, 150 1.91 tsutsui .free_screen = tga_free_screen, 151 1.91 tsutsui .show_screen = tga_show_screen, 152 1.91 tsutsui .load_font = NULL, 153 1.91 tsutsui .pollc = NULL, 154 1.91 tsutsui .scroll = NULL, 155 1.1 drochner }; 156 1.1 drochner 157 1.59 perry static void tga_blank(struct tga_devconfig *); 158 1.59 perry static void tga_unblank(struct tga_devconfig *); 159 1.1 drochner 160 1.1 drochner int 161 1.77 tsutsui tga_cnmatch(bus_space_tag_t iot, bus_space_tag_t memt, 162 1.77 tsutsui pci_chipset_tag_t pc, pcitag_t tag) 163 1.34 elric { 164 1.77 tsutsui 165 1.34 elric return tga_matchcommon(memt, pc, tag); 166 1.34 elric } 167 1.34 elric 168 1.90 tsutsui static int 169 1.74 cegger tgamatch(device_t parent, cfdata_t match, void *aux) 170 1.1 drochner { 171 1.1 drochner struct pci_attach_args *pa = aux; 172 1.1 drochner 173 1.17 elric if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_DEC) 174 1.1 drochner return (0); 175 1.1 drochner 176 1.17 elric switch (PCI_PRODUCT(pa->pa_id)) { 177 1.17 elric case PCI_PRODUCT_DEC_21030: 178 1.17 elric case PCI_PRODUCT_DEC_PBXGB: 179 1.34 elric break; 180 1.17 elric default: 181 1.17 elric return 0; 182 1.17 elric } 183 1.34 elric 184 1.63 rpaulo #if defined(__alpha__) || defined(arc) 185 1.34 elric /* short-circuit the following test, as we 186 1.34 elric * already have the memory mapped and hence 187 1.34 elric * cannot perform it---and we are the console 188 1.34 elric * anyway. 189 1.34 elric */ 190 1.34 elric if (pa->pa_tag == tga_console_dc.dc_pcitag) 191 1.34 elric return 10; 192 1.63 rpaulo #endif 193 1.34 elric return tga_matchcommon(pa->pa_memt, pa->pa_pc, pa->pa_tag); 194 1.34 elric } 195 1.34 elric 196 1.34 elric static int 197 1.70 dsl tga_matchcommon(bus_space_tag_t memt, pci_chipset_tag_t pc, pcitag_t tag) 198 1.34 elric { 199 1.34 elric struct tga_devconfig tmp_dc; 200 1.34 elric struct tga_devconfig *dc = &tmp_dc; 201 1.34 elric bus_size_t pcisize; 202 1.34 elric 203 1.34 elric tga_mapaddrs(memt, pc, tag, &pcisize, dc); 204 1.34 elric dc->dc_tga_type = tga_identify(dc); 205 1.34 elric 206 1.34 elric dc->dc_tgaconf = tga_getconf(dc->dc_tga_type); 207 1.34 elric bus_space_unmap(memt, dc->dc_memh, pcisize); 208 1.34 elric if (dc->dc_tgaconf) 209 1.34 elric return 10; 210 1.34 elric return 0; 211 1.1 drochner } 212 1.1 drochner 213 1.22 nathanw static void 214 1.77 tsutsui tga_mapaddrs(bus_space_tag_t memt, pci_chipset_tag_t pc, pcitag_t tag, 215 1.77 tsutsui bus_size_t *pcisize, struct tga_devconfig *dc) 216 1.1 drochner { 217 1.34 elric int flags; 218 1.1 drochner 219 1.1 drochner dc->dc_memt = memt; 220 1.34 elric dc->dc_tgaconf = NULL; 221 1.1 drochner 222 1.1 drochner /* XXX magic number */ 223 1.1 drochner if (pci_mapreg_info(pc, tag, 0x10, 224 1.1 drochner PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 225 1.34 elric &dc->dc_pcipaddr, pcisize, &flags)) 226 1.34 elric panic("tga_mapaddrs: pci_mapreg_info() failed"); 227 1.16 drochner if ((flags & BUS_SPACE_MAP_PREFETCHABLE) == 0) /* XXX */ 228 1.16 drochner panic("tga memory not prefetchable"); 229 1.1 drochner 230 1.34 elric if (bus_space_map(memt, dc->dc_pcipaddr, *pcisize, 231 1.21 nathanw BUS_SPACE_MAP_PREFETCHABLE | BUS_SPACE_MAP_LINEAR, &dc->dc_memh)) 232 1.34 elric panic("tga_mapaddrs: could not map TGA address space"); 233 1.77 tsutsui dc->dc_vaddr = (vaddr_t)bus_space_vaddr(memt, dc->dc_memh); 234 1.1 drochner 235 1.60 perry bus_space_subregion(dc->dc_memt, dc->dc_memh, 236 1.77 tsutsui TGA_MEM_CREGS, TGA_CREGS_SIZE, &dc->dc_regs); 237 1.34 elric } 238 1.34 elric 239 1.34 elric static void 240 1.77 tsutsui tga_init(bus_space_tag_t memt, pci_chipset_tag_t pc, pcitag_t tag, 241 1.77 tsutsui struct tga_devconfig *dc) 242 1.34 elric { 243 1.34 elric const struct tga_conf *tgac; 244 1.34 elric struct rasops_info *rip; 245 1.34 elric int cookie; 246 1.34 elric bus_size_t pcisize; 247 1.34 elric int i; 248 1.34 elric 249 1.69 ahoka dc->dc_pc = pc; 250 1.34 elric dc->dc_pcitag = tag; 251 1.34 elric tga_mapaddrs(memt, pc, tag, &pcisize, dc); 252 1.21 nathanw dc->dc_tga_type = tga_identify(dc); 253 1.1 drochner tgac = dc->dc_tgaconf = tga_getconf(dc->dc_tga_type); 254 1.1 drochner #if 0 255 1.1 drochner /* XXX on the Alpha, pcisize = 4 * cspace_size. */ 256 1.1 drochner if (tgac->tgac_cspace_size != pcisize) /* sanity */ 257 1.34 elric panic("tga_init: memory size mismatch?"); 258 1.1 drochner #endif 259 1.1 drochner 260 1.21 nathanw switch (TGARREG(dc, TGA_REG_GREV) & 0xff) { 261 1.19 elric case 0x01: 262 1.19 elric case 0x02: 263 1.19 elric case 0x03: 264 1.19 elric case 0x04: 265 1.19 elric dc->dc_tga2 = 0; 266 1.19 elric break; 267 1.19 elric case 0x20: 268 1.19 elric case 0x21: 269 1.19 elric case 0x22: 270 1.19 elric dc->dc_tga2 = 1; 271 1.19 elric break; 272 1.19 elric default: 273 1.34 elric panic("tga_init: TGA Revision not recognized"); 274 1.19 elric } 275 1.19 elric 276 1.38 elric if (dc->dc_tga2) 277 1.38 elric tga2_init(dc); 278 1.60 perry 279 1.21 nathanw switch (TGARREG(dc, TGA_REG_VHCR) & 0x1ff) { /* XXX */ 280 1.1 drochner case 0: 281 1.1 drochner dc->dc_wid = 8192; 282 1.1 drochner break; 283 1.1 drochner 284 1.1 drochner case 1: 285 1.1 drochner dc->dc_wid = 8196; 286 1.1 drochner break; 287 1.1 drochner 288 1.1 drochner default: 289 1.21 nathanw dc->dc_wid = (TGARREG(dc, TGA_REG_VHCR) & 0x1ff) * 4; /* XXX */ 290 1.1 drochner break; 291 1.29 thorpej } 292 1.29 thorpej 293 1.29 thorpej /* 294 1.29 thorpej * XXX XXX Turning off "odd" shouldn't be necessary, 295 1.29 thorpej * XXX XXX but I can't make X work with the weird size. 296 1.29 thorpej */ 297 1.29 thorpej if ((TGARREG(dc, TGA_REG_VHCR) & 0x00000001) != 0 && /* XXX */ 298 1.29 thorpej (TGARREG(dc, TGA_REG_VHCR) & 0x80000000) != 0) { /* XXX */ 299 1.29 thorpej TGAWREG(dc, TGA_REG_VHCR, 300 1.29 thorpej (TGARREG(dc, TGA_REG_VHCR) & ~0x80000001)); 301 1.29 thorpej dc->dc_wid -= 4; 302 1.1 drochner } 303 1.1 drochner 304 1.1 drochner dc->dc_rowbytes = dc->dc_wid * (dc->dc_tgaconf->tgac_phys_depth / 8); 305 1.21 nathanw dc->dc_ht = (TGARREG(dc, TGA_REG_VVCR) & 0x7ff); /* XXX */ 306 1.1 drochner 307 1.1 drochner /* XXX this seems to be what DEC does */ 308 1.21 nathanw TGAWREG(dc, TGA_REG_CCBR, 0); 309 1.21 nathanw TGAWREG(dc, TGA_REG_VVBR, 1); 310 1.1 drochner dc->dc_videobase = dc->dc_vaddr + tgac->tgac_dbuf[0] + 311 1.1 drochner 1 * tgac->tgac_vvbr_units; 312 1.1 drochner dc->dc_blanked = 1; 313 1.1 drochner tga_unblank(dc); 314 1.60 perry 315 1.1 drochner /* 316 1.1 drochner * Set all bits in the pixel mask, to enable writes to all pixels. 317 1.1 drochner * It seems that the console firmware clears some of them 318 1.1 drochner * under some circumstances, which causes cute vertical stripes. 319 1.1 drochner */ 320 1.21 nathanw TGAWREG(dc, TGA_REG_GPXR_P, 0xffffffff); 321 1.1 drochner 322 1.1 drochner /* clear the screen */ 323 1.77 tsutsui for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(uint32_t)) 324 1.77 tsutsui *(uint32_t *)(dc->dc_videobase + i) = 0; 325 1.1 drochner 326 1.23 nathanw /* Initialize rasops descriptor */ 327 1.23 nathanw rip = &dc->dc_rinfo; 328 1.23 nathanw rip->ri_flg = RI_CENTER; 329 1.23 nathanw rip->ri_depth = tgac->tgac_phys_depth; 330 1.23 nathanw rip->ri_bits = (void *)dc->dc_videobase; 331 1.23 nathanw rip->ri_width = dc->dc_wid; 332 1.23 nathanw rip->ri_height = dc->dc_ht; 333 1.23 nathanw rip->ri_stride = dc->dc_rowbytes; 334 1.23 nathanw rip->ri_hw = dc; 335 1.78 tsutsui if (dc == &tga_console_dc) 336 1.78 tsutsui rip->ri_flg |= RI_NO_AUTO; 337 1.23 nathanw 338 1.23 nathanw if (tgac->tgac_phys_depth == 32) { 339 1.23 nathanw rip->ri_rnum = 8; 340 1.23 nathanw rip->ri_gnum = 8; 341 1.23 nathanw rip->ri_bnum = 8; 342 1.23 nathanw rip->ri_rpos = 16; 343 1.23 nathanw rip->ri_gpos = 8; 344 1.23 nathanw rip->ri_bpos = 0; 345 1.23 nathanw } 346 1.23 nathanw 347 1.23 nathanw wsfont_init(); 348 1.23 nathanw /* prefer 8 pixel wide font */ 349 1.40 ad cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_R2L, 350 1.83 macallan WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 351 1.40 ad if (cookie <= 0) 352 1.40 ad cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_R2L, 353 1.83 macallan WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 354 1.23 nathanw if (cookie <= 0) { 355 1.23 nathanw printf("tga: no appropriate fonts.\n"); 356 1.23 nathanw return; 357 1.23 nathanw } 358 1.23 nathanw 359 1.23 nathanw /* the accelerated tga_putchar() needs LSbit left */ 360 1.92 tsutsui if (wsfont_lock(cookie, &rip->ri_font)) { 361 1.23 nathanw printf("tga: couldn't lock font\n"); 362 1.23 nathanw return; 363 1.23 nathanw } 364 1.92 tsutsui rip->ri_wsfcookie = cookie; 365 1.23 nathanw 366 1.23 nathanw rasops_init(rip, 34, 80); 367 1.60 perry 368 1.23 nathanw /* add our accelerated functions */ 369 1.60 perry /* XXX shouldn't have to do this; rasops should leave non-NULL 370 1.23 nathanw * XXX entries alone. 371 1.23 nathanw */ 372 1.92 tsutsui rip->ri_ops.copyrows = tga_copyrows; 373 1.92 tsutsui rip->ri_ops.eraserows = tga_eraserows; 374 1.92 tsutsui rip->ri_ops.erasecols = tga_erasecols; 375 1.92 tsutsui rip->ri_ops.copycols = tga_copycols; 376 1.92 tsutsui rip->ri_ops.putchar = tga_putchar; 377 1.92 tsutsui 378 1.92 tsutsui tga_stdscreen.nrows = rip->ri_rows; 379 1.92 tsutsui tga_stdscreen.ncols = rip->ri_cols; 380 1.92 tsutsui tga_stdscreen.textops = &rip->ri_ops; 381 1.92 tsutsui tga_stdscreen.capabilities = rip->ri_caps; 382 1.1 drochner 383 1.22 nathanw 384 1.22 nathanw dc->dc_intrenabled = 0; 385 1.1 drochner } 386 1.1 drochner 387 1.90 tsutsui static void 388 1.74 cegger tgaattach(device_t parent, device_t self, void *aux) 389 1.1 drochner { 390 1.1 drochner struct pci_attach_args *pa = aux; 391 1.75 cegger struct tga_softc *sc = device_private(self); 392 1.77 tsutsui struct tga_devconfig *dc; 393 1.1 drochner struct wsemuldisplaydev_attach_args aa; 394 1.1 drochner pci_intr_handle_t intrh; 395 1.1 drochner const char *intrstr; 396 1.77 tsutsui uint8_t rev; 397 1.1 drochner int console; 398 1.85 christos char intrbuf[PCI_INTRSTR_LEN]; 399 1.1 drochner 400 1.76 tsutsui sc->sc_dev = self; 401 1.76 tsutsui 402 1.25 soda #if defined(__alpha__) || defined(arc) 403 1.1 drochner console = (pa->pa_tag == tga_console_dc.dc_pcitag); 404 1.1 drochner #else 405 1.1 drochner console = 0; 406 1.1 drochner #endif 407 1.1 drochner if (console) { 408 1.1 drochner sc->sc_dc = &tga_console_dc; 409 1.79 tsutsui sc->sc_dc->dc_rinfo.ri_flg &= ~RI_NO_AUTO; 410 1.1 drochner sc->nscreens = 1; 411 1.1 drochner } else { 412 1.77 tsutsui sc->sc_dc = malloc(sizeof(struct tga_devconfig), M_DEVBUF, 413 1.39 tsutsui M_WAITOK|M_ZERO); 414 1.34 elric tga_init(pa->pa_memt, pa->pa_pc, pa->pa_tag, sc->sc_dc); 415 1.1 drochner } 416 1.53 tsutsui if (sc->sc_dc->dc_vaddr == 0) { 417 1.76 tsutsui aprint_error(": couldn't map memory space; punt!\n"); 418 1.1 drochner return; 419 1.1 drochner } 420 1.1 drochner 421 1.1 drochner /* XXX say what's going on. */ 422 1.1 drochner intrstr = NULL; 423 1.30 sommerfe if (pci_intr_map(pa, &intrh)) { 424 1.76 tsutsui aprint_error(": couldn't map interrupt"); 425 1.17 elric return; 426 1.17 elric } 427 1.85 christos intrstr = pci_intr_string(pa->pa_pc, intrh, intrbuf, sizeof(intrbuf)); 428 1.86 jdolecek sc->sc_intr = pci_intr_establish_xname(pa->pa_pc, intrh, IPL_TTY, 429 1.86 jdolecek tga_intr, sc->sc_dc, device_xname(self)); 430 1.17 elric if (sc->sc_intr == NULL) { 431 1.76 tsutsui aprint_error(": couldn't establish interrupt"); 432 1.17 elric if (intrstr != NULL) 433 1.76 tsutsui aprint_error("at %s", intrstr); 434 1.76 tsutsui aprint_error("\n"); 435 1.17 elric return; 436 1.1 drochner } 437 1.1 drochner 438 1.1 drochner rev = PCI_REVISION(pa->pa_class); 439 1.1 drochner switch (rev) { 440 1.17 elric case 0x1: 441 1.17 elric case 0x2: 442 1.17 elric case 0x3: 443 1.76 tsutsui aprint_normal(": DC21030 step %c", 'A' + rev - 1); 444 1.17 elric break; 445 1.17 elric case 0x20: 446 1.76 tsutsui aprint_normal(": TGA2 abstract software model"); 447 1.17 elric break; 448 1.19 elric case 0x21: 449 1.19 elric case 0x22: 450 1.76 tsutsui aprint_normal(": TGA2 pass %d", rev - 0x20); 451 1.1 drochner break; 452 1.1 drochner 453 1.1 drochner default: 454 1.76 tsutsui aprint_normal("unknown stepping (0x%x)", rev); 455 1.1 drochner break; 456 1.1 drochner } 457 1.76 tsutsui aprint_normal(", "); 458 1.1 drochner 459 1.17 elric /* 460 1.17 elric * Get RAMDAC function vectors and call the RAMDAC functions 461 1.17 elric * to allocate its private storage and pass that back to us. 462 1.17 elric */ 463 1.77 tsutsui 464 1.77 tsutsui dc = sc->sc_dc; 465 1.77 tsutsui dc->dc_ramdac_funcs = dc->dc_tgaconf->ramdac_funcs(); 466 1.77 tsutsui if (!dc->dc_tga2) { 467 1.77 tsutsui if (dc->dc_tgaconf->ramdac_funcs == bt485_funcs) 468 1.77 tsutsui dc->dc_ramdac_cookie = 469 1.77 tsutsui dc->dc_ramdac_funcs->ramdac_register(dc, 470 1.77 tsutsui tga_sched_update, tga_ramdac_wr, tga_ramdac_rd); 471 1.22 nathanw else 472 1.77 tsutsui dc->dc_ramdac_cookie = 473 1.77 tsutsui dc->dc_ramdac_funcs->ramdac_register(dc, 474 1.77 tsutsui tga_sched_update, tga_bt463_wr, tga_bt463_rd); 475 1.17 elric } else { 476 1.77 tsutsui dc->dc_ramdac_cookie = dc->dc_ramdac_funcs->ramdac_register(dc, 477 1.77 tsutsui tga_sched_update, tga2_ramdac_wr, tga2_ramdac_rd); 478 1.38 elric 479 1.38 elric /* XXX this is a bit of a hack, setting the dotclock here */ 480 1.77 tsutsui if (dc->dc_tgaconf->ramdac_funcs != bt485_funcs) 481 1.77 tsutsui (*dc->dc_ramdac_funcs->ramdac_set_dotclock) 482 1.77 tsutsui (dc->dc_ramdac_cookie, tga_getdotclock(dc)); 483 1.17 elric } 484 1.17 elric 485 1.17 elric /* 486 1.17 elric * Initialize the RAMDAC. Initialization includes disabling 487 1.38 elric * cursor, setting a sane colormap, etc. We presume that we've 488 1.38 elric * filled in the necessary dot clock for PowerStorm 4d20. 489 1.17 elric */ 490 1.77 tsutsui (*dc->dc_ramdac_funcs->ramdac_init)(dc->dc_ramdac_cookie); 491 1.77 tsutsui TGAWREG(dc, TGA_REG_SISR, 0x00000001); /* XXX */ 492 1.17 elric 493 1.77 tsutsui if (dc->dc_tgaconf == NULL) { 494 1.76 tsutsui aprint_error("unknown board configuration\n"); 495 1.1 drochner return; 496 1.1 drochner } 497 1.77 tsutsui aprint_normal("board type %s\n", dc->dc_tgaconf->tgac_name); 498 1.76 tsutsui aprint_normal_dev(self, "%d x %d, %dbpp, %s RAMDAC\n", 499 1.77 tsutsui dc->dc_wid, dc->dc_ht, 500 1.77 tsutsui dc->dc_tgaconf->tgac_phys_depth, 501 1.77 tsutsui dc->dc_ramdac_funcs->ramdac_name); 502 1.1 drochner 503 1.1 drochner if (intrstr != NULL) 504 1.76 tsutsui aprint_normal_dev(self, "interrupting at %s\n", 505 1.1 drochner intrstr); 506 1.1 drochner 507 1.1 drochner aa.console = console; 508 1.1 drochner aa.scrdata = &tga_screenlist; 509 1.1 drochner aa.accessops = &tga_accessops; 510 1.1 drochner aa.accesscookie = sc; 511 1.1 drochner 512 1.88 thorpej config_found(self, &aa, wsemuldisplaydevprint, CFARGS_NONE); 513 1.22 nathanw 514 1.22 nathanw config_interrupts(self, tga_config_interrupts); 515 1.22 nathanw } 516 1.22 nathanw 517 1.60 perry static void 518 1.76 tsutsui tga_config_interrupts(device_t self) 519 1.22 nathanw { 520 1.77 tsutsui struct tga_softc *sc; 521 1.77 tsutsui 522 1.77 tsutsui sc = device_private(self); 523 1.22 nathanw sc->sc_dc->dc_intrenabled = 1; 524 1.1 drochner } 525 1.1 drochner 526 1.90 tsutsui static int 527 1.70 dsl tga_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 528 1.1 drochner { 529 1.1 drochner struct tga_softc *sc = v; 530 1.1 drochner struct tga_devconfig *dc = sc->sc_dc; 531 1.17 elric struct ramdac_funcs *dcrf = dc->dc_ramdac_funcs; 532 1.17 elric struct ramdac_cookie *dcrc = dc->dc_ramdac_cookie; 533 1.1 drochner 534 1.1 drochner switch (cmd) { 535 1.1 drochner case WSDISPLAYIO_GTYPE: 536 1.1 drochner *(u_int *)data = WSDISPLAY_TYPE_TGA; 537 1.77 tsutsui return 0; 538 1.1 drochner 539 1.1 drochner case WSDISPLAYIO_GINFO: 540 1.1 drochner #define wsd_fbip ((struct wsdisplay_fbinfo *)data) 541 1.1 drochner wsd_fbip->height = sc->sc_dc->dc_ht; 542 1.1 drochner wsd_fbip->width = sc->sc_dc->dc_wid; 543 1.1 drochner wsd_fbip->depth = sc->sc_dc->dc_tgaconf->tgac_phys_depth; 544 1.38 elric #if 0 545 1.1 drochner wsd_fbip->cmsize = 256; /* XXX ??? */ 546 1.38 elric #else 547 1.38 elric wsd_fbip->cmsize = 1024; /* XXX ??? */ 548 1.38 elric #endif 549 1.12 thorpej #undef wsd_fbip 550 1.77 tsutsui return 0; 551 1.1 drochner 552 1.1 drochner case WSDISPLAYIO_GETCMAP: 553 1.17 elric return (*dcrf->ramdac_get_cmap)(dcrc, 554 1.1 drochner (struct wsdisplay_cmap *)data); 555 1.1 drochner 556 1.1 drochner case WSDISPLAYIO_PUTCMAP: 557 1.17 elric return (*dcrf->ramdac_set_cmap)(dcrc, 558 1.1 drochner (struct wsdisplay_cmap *)data); 559 1.1 drochner 560 1.12 thorpej case WSDISPLAYIO_SVIDEO: 561 1.1 drochner if (*(u_int *)data == WSDISPLAYIO_VIDEO_OFF) 562 1.1 drochner tga_blank(sc->sc_dc); 563 1.1 drochner else 564 1.1 drochner tga_unblank(sc->sc_dc); 565 1.77 tsutsui return 0; 566 1.1 drochner 567 1.12 thorpej case WSDISPLAYIO_GVIDEO: 568 1.1 drochner *(u_int *)data = dc->dc_blanked ? 569 1.1 drochner WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 570 1.77 tsutsui return 0; 571 1.1 drochner 572 1.1 drochner case WSDISPLAYIO_GCURPOS: 573 1.17 elric return (*dcrf->ramdac_get_curpos)(dcrc, 574 1.1 drochner (struct wsdisplay_curpos *)data); 575 1.1 drochner 576 1.1 drochner case WSDISPLAYIO_SCURPOS: 577 1.17 elric return (*dcrf->ramdac_set_curpos)(dcrc, 578 1.1 drochner (struct wsdisplay_curpos *)data); 579 1.1 drochner 580 1.1 drochner case WSDISPLAYIO_GCURMAX: 581 1.17 elric return (*dcrf->ramdac_get_curmax)(dcrc, 582 1.1 drochner (struct wsdisplay_curpos *)data); 583 1.1 drochner 584 1.1 drochner case WSDISPLAYIO_GCURSOR: 585 1.17 elric return (*dcrf->ramdac_get_cursor)(dcrc, 586 1.1 drochner (struct wsdisplay_cursor *)data); 587 1.1 drochner 588 1.1 drochner case WSDISPLAYIO_SCURSOR: 589 1.17 elric return (*dcrf->ramdac_set_cursor)(dcrc, 590 1.1 drochner (struct wsdisplay_cursor *)data); 591 1.69 ahoka 592 1.69 ahoka case WSDISPLAYIO_LINEBYTES: 593 1.69 ahoka *(u_int *)data = dc->dc_rowbytes; 594 1.77 tsutsui return 0; 595 1.69 ahoka 596 1.69 ahoka /* PCI config read/write passthrough. */ 597 1.69 ahoka case PCI_IOC_CFGREAD: 598 1.69 ahoka case PCI_IOC_CFGWRITE: 599 1.77 tsutsui return pci_devioctl(dc->dc_pc, dc->dc_pcitag, 600 1.77 tsutsui cmd, data, flag, l); 601 1.81 cegger 602 1.81 cegger case WSDISPLAYIO_GET_BUSID: 603 1.82 mrg return wsdisplayio_busid_pci(sc->sc_dev, dc->dc_pc, 604 1.81 cegger dc->dc_pcitag, data); 605 1.1 drochner } 606 1.77 tsutsui return EPASSTHROUGH; 607 1.1 drochner } 608 1.1 drochner 609 1.22 nathanw static int 610 1.72 dsl tga_sched_update(void *v, void (*f)(void *)) 611 1.17 elric { 612 1.17 elric struct tga_devconfig *dc = v; 613 1.17 elric 614 1.22 nathanw if (dc->dc_intrenabled) { 615 1.77 tsutsui /* 616 1.77 tsutsui * Arrange for f to be called at the next end-of-frame 617 1.77 tsutsui * interrupt. 618 1.77 tsutsui */ 619 1.22 nathanw dc->dc_ramdac_intr = f; 620 1.22 nathanw TGAWREG(dc, TGA_REG_SISR, 0x00010000); 621 1.22 nathanw } else { 622 1.22 nathanw /* Spin until the end-of-frame, then call f */ 623 1.22 nathanw TGAWREG(dc, TGA_REG_SISR, 0x00010001); 624 1.22 nathanw TGAREGWB(dc, TGA_REG_SISR, 1); 625 1.22 nathanw while ((TGARREG(dc, TGA_REG_SISR) & 0x00000001) == 0) 626 1.77 tsutsui continue; 627 1.22 nathanw f(dc->dc_ramdac_cookie); 628 1.22 nathanw TGAWREG(dc, TGA_REG_SISR, 0x00000001); 629 1.22 nathanw TGAREGWB(dc, TGA_REG_SISR, 1); 630 1.22 nathanw } 631 1.60 perry 632 1.17 elric return 0; 633 1.17 elric } 634 1.17 elric 635 1.22 nathanw static int 636 1.70 dsl tga_intr(void *v) 637 1.17 elric { 638 1.17 elric struct tga_devconfig *dc = v; 639 1.17 elric struct ramdac_cookie *dcrc= dc->dc_ramdac_cookie; 640 1.17 elric 641 1.77 tsutsui uint32_t reg; 642 1.22 nathanw 643 1.22 nathanw reg = TGARREG(dc, TGA_REG_SISR); 644 1.22 nathanw if (( reg & 0x00010001) != 0x00010001) { 645 1.22 nathanw /* Odd. We never set any of the other interrupt enables. */ 646 1.22 nathanw if ((reg & 0x1f) != 0) { 647 1.22 nathanw /* Clear the mysterious pending interrupts. */ 648 1.22 nathanw TGAWREG(dc, TGA_REG_SISR, (reg & 0x1f)); 649 1.22 nathanw TGAREGWB(dc, TGA_REG_SISR, 1); 650 1.77 tsutsui /* 651 1.77 tsutsui * This was our interrupt, even if we're puzzled 652 1.77 tsutsui * as to why we got it. Don't make the interrupt 653 1.77 tsutsui * handler think it was a stray. 654 1.22 nathanw */ 655 1.22 nathanw return -1; 656 1.22 nathanw } else { 657 1.22 nathanw return 0; 658 1.22 nathanw } 659 1.22 nathanw } 660 1.32 elric /* if we have something to do, do it */ 661 1.32 elric if (dc->dc_ramdac_intr) { 662 1.32 elric dc->dc_ramdac_intr(dcrc); 663 1.32 elric dc->dc_ramdac_intr = NULL; 664 1.32 elric } 665 1.21 nathanw TGAWREG(dc, TGA_REG_SISR, 0x00000001); 666 1.22 nathanw TGAREGWB(dc, TGA_REG_SISR, 1); 667 1.77 tsutsui return 1; 668 1.17 elric } 669 1.17 elric 670 1.90 tsutsui static paddr_t 671 1.70 dsl tga_mmap(void *v, void *vs, off_t offset, int prot) 672 1.1 drochner { 673 1.1 drochner struct tga_softc *sc = v; 674 1.1 drochner 675 1.10 mrg if (offset >= sc->sc_dc->dc_tgaconf->tgac_cspace_size || offset < 0) 676 1.1 drochner return -1; 677 1.24 soda 678 1.77 tsutsui return bus_space_mmap(sc->sc_dc->dc_memt, sc->sc_dc->dc_pcipaddr, 679 1.77 tsutsui offset, prot, BUS_SPACE_MAP_LINEAR); 680 1.1 drochner } 681 1.1 drochner 682 1.22 nathanw static int 683 1.77 tsutsui tga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 684 1.77 tsutsui int *curxp, int *curyp, long *attrp) 685 1.1 drochner { 686 1.1 drochner struct tga_softc *sc = v; 687 1.4 drochner long defattr; 688 1.1 drochner 689 1.1 drochner if (sc->nscreens > 0) 690 1.77 tsutsui return ENOMEM; 691 1.1 drochner 692 1.23 nathanw *cookiep = &sc->sc_dc->dc_rinfo; /* one and only for now */ 693 1.1 drochner *curxp = 0; 694 1.1 drochner *curyp = 0; 695 1.60 perry sc->sc_dc->dc_rinfo.ri_ops.allocattr(&sc->sc_dc->dc_rinfo, 696 1.77 tsutsui 0, 0, 0, &defattr); 697 1.4 drochner *attrp = defattr; 698 1.2 drochner sc->nscreens++; 699 1.77 tsutsui return 0; 700 1.1 drochner } 701 1.1 drochner 702 1.22 nathanw static void 703 1.70 dsl tga_free_screen(void *v, void *cookie) 704 1.1 drochner { 705 1.1 drochner struct tga_softc *sc = v; 706 1.1 drochner 707 1.1 drochner if (sc->sc_dc == &tga_console_dc) 708 1.1 drochner panic("tga_free_screen: console"); 709 1.1 drochner 710 1.1 drochner sc->nscreens--; 711 1.1 drochner } 712 1.1 drochner 713 1.22 nathanw static int 714 1.77 tsutsui tga_show_screen(void *v, void *cookie, int waitok, 715 1.77 tsutsui void (*cb)(void *, int, int), void *cbarg) 716 1.1 drochner { 717 1.15 drochner 718 1.77 tsutsui return 0; 719 1.1 drochner } 720 1.1 drochner 721 1.1 drochner int 722 1.77 tsutsui tga_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, 723 1.77 tsutsui pci_chipset_tag_t pc, int bus, int device, int function) 724 1.1 drochner { 725 1.1 drochner struct tga_devconfig *dcp = &tga_console_dc; 726 1.4 drochner long defattr; 727 1.1 drochner 728 1.34 elric tga_init(memt, pc, pci_make_tag(pc, bus, device, function), dcp); 729 1.1 drochner 730 1.1 drochner /* sanity checks */ 731 1.53 tsutsui if (dcp->dc_vaddr == 0) 732 1.1 drochner panic("tga_console(%d, %d): couldn't map memory space", 733 1.1 drochner device, function); 734 1.1 drochner if (dcp->dc_tgaconf == NULL) 735 1.1 drochner panic("tga_console(%d, %d): unknown board configuration", 736 1.1 drochner device, function); 737 1.1 drochner 738 1.1 drochner /* 739 1.1 drochner * Initialize the RAMDAC but DO NOT allocate any private storage. 740 1.1 drochner * Initialization includes disabling cursor, setting a sane 741 1.1 drochner * colormap, etc. It will be reinitialized in tgaattach(). 742 1.1 drochner */ 743 1.38 elric if (dcp->dc_tga2) { 744 1.38 elric if (dcp->dc_tgaconf->ramdac_funcs == bt485_funcs) 745 1.38 elric bt485_cninit(dcp, tga_sched_update, tga2_ramdac_wr, 746 1.38 elric tga2_ramdac_rd); 747 1.38 elric else 748 1.38 elric ibm561_cninit(dcp, tga_sched_update, tga2_ramdac_wr, 749 1.38 elric tga2_ramdac_rd, tga_getdotclock(dcp)); 750 1.38 elric } else { 751 1.23 nathanw if (dcp->dc_tgaconf->ramdac_funcs == bt485_funcs) 752 1.23 nathanw bt485_cninit(dcp, tga_sched_update, tga_ramdac_wr, 753 1.77 tsutsui tga_ramdac_rd); 754 1.23 nathanw else { 755 1.23 nathanw bt463_cninit(dcp, tga_sched_update, tga_bt463_wr, 756 1.77 tsutsui tga_bt463_rd); 757 1.23 nathanw } 758 1.23 nathanw } 759 1.42 junyoung dcp->dc_rinfo.ri_ops.allocattr(&dcp->dc_rinfo, 0, 0, 0, &defattr); 760 1.23 nathanw wsdisplay_cnattach(&tga_stdscreen, &dcp->dc_rinfo, 0, 0, defattr); 761 1.60 perry 762 1.77 tsutsui return 0; 763 1.1 drochner } 764 1.1 drochner 765 1.1 drochner /* 766 1.1 drochner * Functions to blank and unblank the display. 767 1.1 drochner */ 768 1.22 nathanw static void 769 1.70 dsl tga_blank(struct tga_devconfig *dc) 770 1.1 drochner { 771 1.1 drochner 772 1.1 drochner if (!dc->dc_blanked) { 773 1.1 drochner dc->dc_blanked = 1; 774 1.21 nathanw /* XXX */ 775 1.77 tsutsui TGAWREG(dc, TGA_REG_VVVR, 776 1.77 tsutsui TGARREG(dc, TGA_REG_VVVR) | VVR_BLANK); 777 1.1 drochner } 778 1.1 drochner } 779 1.1 drochner 780 1.22 nathanw static void 781 1.70 dsl tga_unblank(struct tga_devconfig *dc) 782 1.1 drochner { 783 1.1 drochner 784 1.1 drochner if (dc->dc_blanked) { 785 1.1 drochner dc->dc_blanked = 0; 786 1.21 nathanw /* XXX */ 787 1.77 tsutsui TGAWREG(dc, TGA_REG_VVVR, 788 1.77 tsutsui TGARREG(dc, TGA_REG_VVVR) & ~VVR_BLANK); 789 1.1 drochner } 790 1.1 drochner } 791 1.1 drochner 792 1.1 drochner /* 793 1.1 drochner * Functions to manipulate the built-in cursor handing hardware. 794 1.1 drochner */ 795 1.1 drochner int 796 1.77 tsutsui tga_builtin_set_cursor(struct tga_devconfig *dc, 797 1.77 tsutsui struct wsdisplay_cursor *cursorp) 798 1.1 drochner { 799 1.17 elric struct ramdac_funcs *dcrf = dc->dc_ramdac_funcs; 800 1.17 elric struct ramdac_cookie *dcrc = dc->dc_ramdac_cookie; 801 1.77 tsutsui uint8_t image[512]; 802 1.35 jdolecek u_int count, v; 803 1.35 jdolecek int error; 804 1.1 drochner 805 1.1 drochner v = cursorp->which; 806 1.8 thorpej if (v & WSDISPLAY_CURSOR_DOCMAP) { 807 1.17 elric error = dcrf->ramdac_check_curcmap(dcrc, cursorp); 808 1.8 thorpej if (error) 809 1.77 tsutsui return error; 810 1.8 thorpej } 811 1.1 drochner if (v & WSDISPLAY_CURSOR_DOSHAPE) { 812 1.1 drochner if ((u_int)cursorp->size.x != 64 || 813 1.1 drochner (u_int)cursorp->size.y > 64) 814 1.77 tsutsui return EINVAL; 815 1.1 drochner /* The cursor is 2 bits deep, and there is no mask */ 816 1.1 drochner count = (cursorp->size.y * 64 * 2) / NBBY; 817 1.57 chs error = copyin(cursorp->image, image, count); 818 1.57 chs if (error) 819 1.57 chs return error; 820 1.1 drochner } 821 1.1 drochner if (v & WSDISPLAY_CURSOR_DOHOT) /* not supported */ 822 1.1 drochner return EINVAL; 823 1.1 drochner 824 1.1 drochner /* parameters are OK; do it */ 825 1.1 drochner if (v & WSDISPLAY_CURSOR_DOCUR) { 826 1.1 drochner if (cursorp->enable) 827 1.21 nathanw /* XXX */ 828 1.57 chs TGAWREG(dc, TGA_REG_VVVR, 829 1.77 tsutsui TGARREG(dc, TGA_REG_VVVR) | 0x04); 830 1.1 drochner else 831 1.21 nathanw /* XXX */ 832 1.57 chs TGAWREG(dc, TGA_REG_VVVR, 833 1.77 tsutsui TGARREG(dc, TGA_REG_VVVR) & ~0x04); 834 1.1 drochner } 835 1.1 drochner if (v & WSDISPLAY_CURSOR_DOPOS) { 836 1.57 chs TGAWREG(dc, TGA_REG_CXYR, ((cursorp->pos.y & 0xfff) << 12) | 837 1.77 tsutsui (cursorp->pos.x & 0xfff)); 838 1.1 drochner } 839 1.1 drochner if (v & WSDISPLAY_CURSOR_DOCMAP) { 840 1.17 elric dcrf->ramdac_set_curcmap(dcrc, cursorp); 841 1.1 drochner } 842 1.1 drochner if (v & WSDISPLAY_CURSOR_DOSHAPE) { 843 1.8 thorpej count = ((64 * 2) / NBBY) * cursorp->size.y; 844 1.21 nathanw TGAWREG(dc, TGA_REG_CCBR, 845 1.57 chs (TGARREG(dc, TGA_REG_CCBR) & ~0xfc00) | 846 1.57 chs (cursorp->size.y << 10)); 847 1.77 tsutsui memcpy((void *)(dc->dc_vaddr + 848 1.77 tsutsui (TGARREG(dc, TGA_REG_CCBR) & 0x3ff)), 849 1.77 tsutsui image, count); 850 1.1 drochner } 851 1.77 tsutsui return 0; 852 1.1 drochner } 853 1.1 drochner 854 1.1 drochner int 855 1.77 tsutsui tga_builtin_get_cursor(struct tga_devconfig *dc, 856 1.77 tsutsui struct wsdisplay_cursor *cursorp) 857 1.1 drochner { 858 1.17 elric struct ramdac_funcs *dcrf = dc->dc_ramdac_funcs; 859 1.17 elric struct ramdac_cookie *dcrc = dc->dc_ramdac_cookie; 860 1.1 drochner int count, error; 861 1.1 drochner 862 1.1 drochner cursorp->which = WSDISPLAY_CURSOR_DOALL & 863 1.1 drochner ~(WSDISPLAY_CURSOR_DOHOT | WSDISPLAY_CURSOR_DOCMAP); 864 1.21 nathanw cursorp->enable = (TGARREG(dc, TGA_REG_VVVR) & 0x04) != 0; 865 1.21 nathanw cursorp->pos.x = TGARREG(dc, TGA_REG_CXYR) & 0xfff; 866 1.21 nathanw cursorp->pos.y = (TGARREG(dc, TGA_REG_CXYR) >> 12) & 0xfff; 867 1.1 drochner cursorp->size.x = 64; 868 1.21 nathanw cursorp->size.y = (TGARREG(dc, TGA_REG_CCBR) >> 10) & 0x3f; 869 1.1 drochner 870 1.1 drochner if (cursorp->image != NULL) { 871 1.1 drochner count = (cursorp->size.y * 64 * 2) / NBBY; 872 1.1 drochner error = copyout((char *)(dc->dc_vaddr + 873 1.77 tsutsui (TGARREG(dc, TGA_REG_CCBR) & 0x3ff)), 874 1.1 drochner cursorp->image, count); 875 1.1 drochner if (error) 876 1.77 tsutsui return error; 877 1.1 drochner /* No mask */ 878 1.1 drochner } 879 1.17 elric error = dcrf->ramdac_get_curcmap(dcrc, cursorp); 880 1.77 tsutsui return error; 881 1.1 drochner } 882 1.1 drochner 883 1.1 drochner int 884 1.77 tsutsui tga_builtin_set_curpos(struct tga_devconfig *dc, 885 1.77 tsutsui struct wsdisplay_curpos *curposp) 886 1.1 drochner { 887 1.1 drochner 888 1.21 nathanw TGAWREG(dc, TGA_REG_CXYR, 889 1.21 nathanw ((curposp->y & 0xfff) << 12) | (curposp->x & 0xfff)); 890 1.77 tsutsui return 0; 891 1.1 drochner } 892 1.1 drochner 893 1.1 drochner int 894 1.77 tsutsui tga_builtin_get_curpos(struct tga_devconfig *dc, 895 1.77 tsutsui struct wsdisplay_curpos *curposp) 896 1.1 drochner { 897 1.1 drochner 898 1.21 nathanw curposp->x = TGARREG(dc, TGA_REG_CXYR) & 0xfff; 899 1.21 nathanw curposp->y = (TGARREG(dc, TGA_REG_CXYR) >> 12) & 0xfff; 900 1.77 tsutsui return 0; 901 1.1 drochner } 902 1.1 drochner 903 1.1 drochner int 904 1.77 tsutsui tga_builtin_get_curmax(struct tga_devconfig *dc, 905 1.77 tsutsui struct wsdisplay_curpos *curposp) 906 1.1 drochner { 907 1.1 drochner 908 1.1 drochner curposp->x = curposp->y = 64; 909 1.77 tsutsui return 0; 910 1.14 ross } 911 1.14 ross 912 1.14 ross /* 913 1.14 ross * Copy columns (characters) in a row (line). 914 1.14 ross */ 915 1.22 nathanw static void 916 1.71 dsl tga_copycols(void *id, int row, int srccol, int dstcol, int ncols) 917 1.14 ross { 918 1.23 nathanw struct rasops_info *ri = id; 919 1.14 ross int y, srcx, dstx, nx; 920 1.14 ross 921 1.23 nathanw y = ri->ri_font->fontheight * row; 922 1.23 nathanw srcx = ri->ri_font->fontwidth * srccol; 923 1.23 nathanw dstx = ri->ri_font->fontwidth * dstcol; 924 1.23 nathanw nx = ri->ri_font->fontwidth * ncols; 925 1.23 nathanw 926 1.23 nathanw tga_rop(ri, dstx, y, 927 1.23 nathanw nx, ri->ri_font->fontheight, RAS_SRC, 928 1.23 nathanw ri, srcx, y); 929 1.14 ross } 930 1.14 ross 931 1.14 ross /* 932 1.14 ross * Copy rows (lines). 933 1.14 ross */ 934 1.22 nathanw static void 935 1.71 dsl tga_copyrows(void *id, int srcrow, int dstrow, int nrows) 936 1.14 ross { 937 1.23 nathanw struct rasops_info *ri = id; 938 1.14 ross int srcy, dsty, ny; 939 1.14 ross 940 1.23 nathanw srcy = ri->ri_font->fontheight * srcrow; 941 1.23 nathanw dsty = ri->ri_font->fontheight * dstrow; 942 1.23 nathanw ny = ri->ri_font->fontheight * nrows; 943 1.23 nathanw 944 1.23 nathanw tga_rop(ri, 0, dsty, 945 1.23 nathanw ri->ri_emuwidth, ny, RAS_SRC, 946 1.23 nathanw ri, 0, srcy); 947 1.14 ross } 948 1.14 ross 949 1.14 ross /* Do we need the src? */ 950 1.77 tsutsui static const int needsrc[16] = 951 1.77 tsutsui { 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 }; 952 1.14 ross 953 1.14 ross /* A mapping between our API and the TGA card */ 954 1.77 tsutsui static const int map_rop[16] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 955 1.77 tsutsui 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf 956 1.14 ross }; 957 1.14 ross 958 1.14 ross /* 959 1.14 ross * Generic TGA raster op. 960 1.14 ross * This covers all possible raster ops, and 961 1.14 ross * clips the sizes and all of that. 962 1.14 ross */ 963 1.14 ross static int 964 1.77 tsutsui tga_rop(struct rasops_info *dst, int dx, int dy, int w, int h, int rop, 965 1.77 tsutsui struct rasops_info *src, int sx, int sy) 966 1.14 ross { 967 1.77 tsutsui 968 1.77 tsutsui if (dst == NULL) 969 1.14 ross return -1; 970 1.14 ross if (needsrc[RAS_GETOP(rop)]) { 971 1.23 nathanw if (src == NULL) 972 1.14 ross return -1; /* We want a src */ 973 1.14 ross /* Clip against src */ 974 1.14 ross if (sx < 0) { 975 1.14 ross w += sx; 976 1.14 ross sx = 0; 977 1.14 ross } 978 1.14 ross if (sy < 0) { 979 1.14 ross h += sy; 980 1.14 ross sy = 0; 981 1.14 ross } 982 1.23 nathanw if (sx + w > src->ri_emuwidth) 983 1.23 nathanw w = src->ri_emuwidth - sx; 984 1.23 nathanw if (sy + h > src->ri_emuheight) 985 1.23 nathanw h = src->ri_emuheight - sy; 986 1.14 ross } else { 987 1.23 nathanw if (src != NULL) 988 1.14 ross return -1; /* We need no src */ 989 1.14 ross } 990 1.14 ross /* Clip against dst. We modify src regardless of using it, 991 1.14 ross * since it really doesn't matter. 992 1.14 ross */ 993 1.14 ross if (dx < 0) { 994 1.14 ross w += dx; 995 1.14 ross sx -= dx; 996 1.14 ross dx = 0; 997 1.14 ross } 998 1.14 ross if (dy < 0) { 999 1.14 ross h += dy; 1000 1.14 ross sy -= dy; 1001 1.14 ross dy = 0; 1002 1.14 ross } 1003 1.23 nathanw if (dx + w > dst->ri_emuwidth) 1004 1.23 nathanw w = dst->ri_emuwidth - dx; 1005 1.23 nathanw if (dy + h > dst->ri_emuheight) 1006 1.23 nathanw h = dst->ri_emuheight - dy; 1007 1.14 ross if (w <= 0 || h <= 0) 1008 1.14 ross return 0; /* Vacuously true; */ 1009 1.77 tsutsui if (src == NULL) { 1010 1.23 nathanw /* XXX Punt! */ 1011 1.23 nathanw return -1; 1012 1.23 nathanw } 1013 1.23 nathanw return tga_rop_vtov(dst, dx, dy, w, h, rop, src, sx, sy); 1014 1.14 ross } 1015 1.14 ross 1016 1.14 ross 1017 1.14 ross 1018 1.14 ross /* 1019 1.14 ross * Video to Video raster ops. 1020 1.14 ross * This function deals with all raster ops that have a src and dst 1021 1.14 ross * that are on the card. 1022 1.14 ross */ 1023 1.14 ross static int 1024 1.77 tsutsui tga_rop_vtov(struct rasops_info *dst, int dx, int dy, int w, int h, int rop, 1025 1.77 tsutsui struct rasops_info *src, int sx, int sy) 1026 1.14 ross { 1027 1.77 tsutsui struct tga_devconfig *dc = dst->ri_hw; 1028 1.31 nathanw int srcb, dstb, tga_srcb, tga_dstb; 1029 1.31 nathanw int x, y, wb; 1030 1.84 christos int xstart, xdir; 1031 1.14 ross int ystart, yend, ydir, yinc; 1032 1.55 mycroft int xleft, lastx, lastleft; 1033 1.14 ross int offset = 1 * dc->dc_tgaconf->tgac_vvbr_units; 1034 1.14 ross 1035 1.14 ross /* 1036 1.14 ross * I don't yet want to deal with unaligned guys, really. And we don't 1037 1.14 ross * deal with copies from one card to another. 1038 1.14 ross */ 1039 1.23 nathanw if (dx % 8 != 0 || sx % 8 != 0 || src != dst) { 1040 1.23 nathanw /* XXX Punt! */ 1041 1.23 nathanw /* XXX should never happen, since it's only being used to 1042 1.23 nathanw * XXX copy 8-pixel-wide characters. 1043 1.23 nathanw */ 1044 1.23 nathanw return -1; 1045 1.23 nathanw } 1046 1.14 ross 1047 1.77 tsutsui srcb = sy * src->ri_stride + sx * (src->ri_depth / 8); 1048 1.77 tsutsui dstb = dy * dst->ri_stride + dx * (dst->ri_depth / 8); 1049 1.60 perry tga_srcb = offset + (sy + src->ri_yorigin) * src->ri_stride + 1050 1.77 tsutsui (sx + src->ri_xorigin) * (src->ri_depth / 8); 1051 1.60 perry tga_dstb = offset + (dy + dst->ri_yorigin) * dst->ri_stride + 1052 1.77 tsutsui (dx + dst->ri_xorigin) * (dst->ri_depth / 8); 1053 1.43 mycroft 1054 1.14 ross if (sy >= dy) { 1055 1.14 ross ystart = 0; 1056 1.43 mycroft yend = (h - 1) * dst->ri_stride; 1057 1.14 ross ydir = 1; 1058 1.14 ross } else { 1059 1.43 mycroft ystart = (h - 1) * dst->ri_stride; 1060 1.14 ross yend = 0; 1061 1.14 ross ydir = -1; 1062 1.14 ross } 1063 1.43 mycroft yinc = ydir * dst->ri_stride; 1064 1.43 mycroft 1065 1.43 mycroft wb = w * (dst->ri_depth / 8); 1066 1.44 mycroft if (sx >= dx || (sx + w) <= dx) { /* copy forwards */ 1067 1.14 ross xstart = 0; 1068 1.14 ross xdir = 1; 1069 1.44 mycroft } else { /* copy backwards */ 1070 1.43 mycroft xstart = wb; 1071 1.14 ross xdir = -1; 1072 1.14 ross } 1073 1.31 nathanw 1074 1.45 mycroft TGAWALREG(dc, TGA_REG_GMOR, 3, 0x0007); /* Copy mode */ 1075 1.31 nathanw TGAWALREG(dc, TGA_REG_GOPR, 3, map_rop[rop]); /* Set up the op */ 1076 1.45 mycroft TGAWALREG(dc, TGA_REG_GPSR, 3, 0); /* No shift */ 1077 1.31 nathanw 1078 1.31 nathanw /* 1079 1.31 nathanw * we have 3 sizes of pixels to move in X direction: 1080 1.31 nathanw * 4 * 64 (unrolled TGA ops) 1081 1.31 nathanw * 64 (single TGA op) 1082 1.31 nathanw * 4 (CPU, using long word) 1083 1.31 nathanw */ 1084 1.31 nathanw 1085 1.31 nathanw if (xdir == 1) { /* move to the left */ 1086 1.31 nathanw 1087 1.56 mycroft if (wb & ~63) 1088 1.31 nathanw for (y = ystart; (ydir * y) <= (ydir * yend); y += yinc) { 1089 1.77 tsutsui /* 4 * 64 byte chunks */ 1090 1.77 tsutsui for (xleft = wb, x = xstart; xleft >= 4 * 64; 1091 1.77 tsutsui x += 4 * 64, xleft -= 4 * 64) { 1092 1.77 tsutsui 1093 1.77 tsutsui /* 1094 1.77 tsutsui * XXX XXX Eight writes to different addresses 1095 1.77 tsutsui * XXX XXX should fill up the write buffers on 1096 1.77 tsutsui * XXX XXX 21064 and 21164 chips, but later 1097 1.77 tsutsui * XXX XXX CPUs might have larger write buffers 1098 1.77 tsutsui * XXX XXX which require further unrolling of 1099 1.77 tsutsui * XXX XXX this loop, or the insertion of 1100 1.77 tsutsui * XXX XXX memory barriers. 1101 1.31 nathanw */ 1102 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCSR, 0, 1103 1.77 tsutsui tga_srcb + y + x + 0 * 64); 1104 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCDR, 0, 1105 1.77 tsutsui tga_dstb + y + x + 0 * 64); 1106 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCSR, 1, 1107 1.77 tsutsui tga_srcb + y + x + 1 * 64); 1108 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCDR, 1, 1109 1.77 tsutsui tga_dstb + y + x + 1 * 64); 1110 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCSR, 2, 1111 1.77 tsutsui tga_srcb + y + x + 2 * 64); 1112 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCDR, 2, 1113 1.77 tsutsui tga_dstb + y + x + 2 * 64); 1114 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCSR, 3, 1115 1.77 tsutsui tga_srcb + y + x + 3 * 64); 1116 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCDR, 3, 1117 1.77 tsutsui tga_dstb + y + x + 3 * 64); 1118 1.31 nathanw } 1119 1.31 nathanw 1120 1.31 nathanw /* 64 byte chunks */ 1121 1.43 mycroft for (; xleft >= 64; x += 64, xleft -= 64) { 1122 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCSR, 0, 1123 1.77 tsutsui tga_srcb + y + x + 0 * 64); 1124 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCDR, 0, 1125 1.77 tsutsui tga_dstb + y + x + 0 * 64); 1126 1.31 nathanw } 1127 1.55 mycroft } 1128 1.43 mycroft 1129 1.31 nathanw TGAWALREG(dc, TGA_REG_GOPR, 0, 0x0003); /* op -> dst = src */ 1130 1.31 nathanw TGAWALREG(dc, TGA_REG_GMOR, 0, 0x0000); /* Simple mode */ 1131 1.31 nathanw 1132 1.55 mycroft lastleft = wb & 63; 1133 1.43 mycroft if (lastleft) { 1134 1.55 mycroft lastx = xstart + (wb & ~63); 1135 1.77 tsutsui for (y = ystart; (ydir * y) <= (ydir * yend); 1136 1.77 tsutsui y += yinc) { 1137 1.43 mycroft /* 4 byte granularity */ 1138 1.43 mycroft for (x = lastx, xleft = lastleft; xleft >= 4; 1139 1.43 mycroft x += 4, xleft -= 4) { 1140 1.77 tsutsui *(uint32_t *)(dst->ri_bits + dstb + 1141 1.77 tsutsui y + x + 0 * 4) = 1142 1.77 tsutsui *(uint32_t *)(dst->ri_bits + srcb + 1143 1.77 tsutsui y + x + 0 * 4); 1144 1.43 mycroft } 1145 1.31 nathanw } 1146 1.31 nathanw } 1147 1.77 tsutsui } else { /* above move to the left, below move to the right */ 1148 1.31 nathanw 1149 1.56 mycroft if (wb & ~63) 1150 1.31 nathanw for (y = ystart; (ydir * y) <= (ydir * yend); y += yinc) { 1151 1.77 tsutsui /* 4 * 64 byte chunks */ 1152 1.77 tsutsui for (xleft = wb, x = xstart; xleft >= 4 * 64; 1153 1.77 tsutsui x -= 4 * 64, xleft -= 4 * 64) { 1154 1.77 tsutsui 1155 1.77 tsutsui /* 1156 1.77 tsutsui * XXX XXX Eight writes to different addresses 1157 1.77 tsutsui * XXX XXX should fill up the write buffers on 1158 1.77 tsutsui * XXX XXX 21064 and 21164 chips, but later 1159 1.77 tsutsui * XXX XXX CPUs might have larger write buffers 1160 1.77 tsutsui * XXX XXX which require further unrolling of 1161 1.77 tsutsui * XXX XXX this loop, or the insertion of 1162 1.77 tsutsui * XXX XXX memory barriers. 1163 1.31 nathanw */ 1164 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCSR, 0, 1165 1.77 tsutsui tga_srcb + y + x - 1 * 64); 1166 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCDR, 0, 1167 1.77 tsutsui tga_dstb + y + x - 1 * 64); 1168 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCSR, 1, 1169 1.77 tsutsui tga_srcb + y + x - 2 * 64); 1170 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCDR, 1, 1171 1.77 tsutsui tga_dstb + y + x - 2 * 64); 1172 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCSR, 2, 1173 1.77 tsutsui tga_srcb + y + x - 3 * 64); 1174 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCDR, 2, 1175 1.77 tsutsui tga_dstb + y + x - 3 * 64); 1176 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCSR, 3, 1177 1.77 tsutsui tga_srcb + y + x - 4 * 64); 1178 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCDR, 3, 1179 1.77 tsutsui tga_dstb + y + x - 4 * 64); 1180 1.31 nathanw } 1181 1.31 nathanw 1182 1.31 nathanw /* 64 byte chunks */ 1183 1.43 mycroft for (; xleft >= 64; x -= 64, xleft -= 64) { 1184 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCSR, 0, 1185 1.77 tsutsui tga_srcb + y + x - 1 * 64); 1186 1.77 tsutsui TGAWALREG(dc, TGA_REG_GCDR, 0, 1187 1.77 tsutsui tga_dstb + y + x - 1 * 64); 1188 1.31 nathanw } 1189 1.55 mycroft } 1190 1.43 mycroft 1191 1.31 nathanw TGAWALREG(dc, TGA_REG_GOPR, 0, 0x0003); /* op -> dst = src */ 1192 1.31 nathanw TGAWALREG(dc, TGA_REG_GMOR, 0, 0x0000); /* Simple mode */ 1193 1.31 nathanw 1194 1.55 mycroft lastleft = wb & 63; 1195 1.43 mycroft if (lastleft) { 1196 1.55 mycroft lastx = xstart - (wb & ~63); 1197 1.77 tsutsui for (y = ystart; (ydir * y) <= (ydir * yend); 1198 1.77 tsutsui y += yinc) { 1199 1.43 mycroft /* 4 byte granularity */ 1200 1.43 mycroft for (x = lastx, xleft = lastleft; xleft >= 4; 1201 1.77 tsutsui x -= 4, xleft -= 4) { 1202 1.77 tsutsui *(uint32_t *)(dst->ri_bits + dstb + 1203 1.77 tsutsui y + x - 1 * 4) = 1204 1.77 tsutsui *(uint32_t *)(dst->ri_bits + srcb + 1205 1.77 tsutsui y + x - 1 * 4); 1206 1.43 mycroft } 1207 1.31 nathanw } 1208 1.14 ross } 1209 1.14 ross } 1210 1.14 ross return 0; 1211 1.17 elric } 1212 1.23 nathanw 1213 1.23 nathanw 1214 1.90 tsutsui static void 1215 1.90 tsutsui tga_putchar(void *c, int row, int col, u_int uc, long attr) 1216 1.23 nathanw { 1217 1.23 nathanw struct rasops_info *ri = c; 1218 1.23 nathanw struct tga_devconfig *dc = ri->ri_hw; 1219 1.23 nathanw int fs, height, width; 1220 1.77 tsutsui uint8_t *fr; 1221 1.23 nathanw int32_t *rp; 1222 1.23 nathanw 1223 1.77 tsutsui rp = (int32_t *)(ri->ri_bits + 1224 1.77 tsutsui row * ri->ri_yscale + col * ri->ri_xscale); 1225 1.23 nathanw 1226 1.23 nathanw height = ri->ri_font->fontheight; 1227 1.23 nathanw width = ri->ri_font->fontwidth; 1228 1.23 nathanw 1229 1.23 nathanw uc -= ri->ri_font->firstchar; 1230 1.77 tsutsui fr = (uint8_t *)ri->ri_font->data + uc * ri->ri_fontscale; 1231 1.23 nathanw fs = ri->ri_font->stride; 1232 1.23 nathanw 1233 1.23 nathanw /* Set foreground and background color. XXX memoize this somehow? 1234 1.23 nathanw * The rasops code has already expanded the color entry to 32 bits 1235 1.23 nathanw * for us, even for 8-bit displays, so we don't have to do anything. 1236 1.23 nathanw */ 1237 1.23 nathanw TGAWREG(dc, TGA_REG_GFGR, ri->ri_devcmap[(attr >> 24) & 15]); 1238 1.23 nathanw TGAWREG(dc, TGA_REG_GBGR, ri->ri_devcmap[(attr >> 16) & 15]); 1239 1.60 perry 1240 1.23 nathanw /* Set raster operation to "copy"... */ 1241 1.23 nathanw if (ri->ri_depth == 8) 1242 1.23 nathanw TGAWREG(dc, TGA_REG_GOPR, 0x3); 1243 1.23 nathanw else /* ... and in 24-bit mode, set the destination bitmap to 24-bit. */ 1244 1.23 nathanw TGAWREG(dc, TGA_REG_GOPR, 0x3 | (0x3 << 8)); 1245 1.23 nathanw 1246 1.23 nathanw /* Set which pixels we're drawing (of a possible 32). */ 1247 1.23 nathanw TGAWREG(dc, TGA_REG_GPXR_P, (1 << width) - 1); 1248 1.23 nathanw 1249 1.23 nathanw /* Set drawing mode to opaque stipple. */ 1250 1.23 nathanw TGAWREG(dc, TGA_REG_GMOR, 0x1); 1251 1.60 perry 1252 1.23 nathanw /* Insert write barrier before actually sending data */ 1253 1.23 nathanw /* XXX Abuses the fact that there is only one write barrier on Alphas */ 1254 1.23 nathanw TGAREGWB(dc, TGA_REG_GMOR, 1); 1255 1.23 nathanw 1256 1.77 tsutsui while (height--) { 1257 1.23 nathanw /* The actual stipple write */ 1258 1.60 perry *rp = fr[0] | (fr[1] << 8) | (fr[2] << 16) | (fr[3] << 24); 1259 1.60 perry 1260 1.23 nathanw fr += fs; 1261 1.77 tsutsui rp = (int32_t *)((uint8_t *)rp + ri->ri_stride); 1262 1.23 nathanw } 1263 1.23 nathanw 1264 1.23 nathanw /* Do underline */ 1265 1.23 nathanw if ((attr & 1) != 0) { 1266 1.77 tsutsui rp = (int32_t *)((uint8_t *)rp - (ri->ri_stride << 1)); 1267 1.23 nathanw *rp = 0xffffffff; 1268 1.23 nathanw } 1269 1.23 nathanw 1270 1.89 andvar /* Set graphics mode back to normal. */ 1271 1.23 nathanw TGAWREG(dc, TGA_REG_GMOR, 0); 1272 1.23 nathanw TGAWREG(dc, TGA_REG_GPXR_P, 0xffffffff); 1273 1.23 nathanw } 1274 1.23 nathanw 1275 1.23 nathanw static void 1276 1.71 dsl tga_eraserows(void *c, int row, int num, long attr) 1277 1.23 nathanw { 1278 1.23 nathanw struct rasops_info *ri = c; 1279 1.23 nathanw struct tga_devconfig *dc = ri->ri_hw; 1280 1.23 nathanw int32_t color, lines, pixels; 1281 1.23 nathanw int32_t *rp; 1282 1.23 nathanw 1283 1.23 nathanw color = ri->ri_devcmap[(attr >> 16) & 15]; 1284 1.23 nathanw rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale); 1285 1.23 nathanw lines = num * ri->ri_font->fontheight; 1286 1.23 nathanw pixels = ri->ri_emuwidth - 1; 1287 1.23 nathanw 1288 1.23 nathanw /* Set fill color in block-color registers */ 1289 1.23 nathanw TGAWREG(dc, TGA_REG_GBCR0, color); 1290 1.23 nathanw TGAWREG(dc, TGA_REG_GBCR1, color); 1291 1.23 nathanw if (ri->ri_depth != 8) { 1292 1.23 nathanw TGAWREG(dc, TGA_REG_GBCR2, color); 1293 1.23 nathanw TGAWREG(dc, TGA_REG_GBCR3, color); 1294 1.23 nathanw TGAWREG(dc, TGA_REG_GBCR4, color); 1295 1.23 nathanw TGAWREG(dc, TGA_REG_GBCR5, color); 1296 1.23 nathanw TGAWREG(dc, TGA_REG_GBCR6, color); 1297 1.23 nathanw TGAWREG(dc, TGA_REG_GBCR7, color); 1298 1.23 nathanw } 1299 1.23 nathanw 1300 1.23 nathanw /* Set raster operation to "copy"... */ 1301 1.23 nathanw if (ri->ri_depth == 8) 1302 1.23 nathanw TGAWREG(dc, TGA_REG_GOPR, 0x3); 1303 1.23 nathanw else /* ... and in 24-bit mode, set the destination bitmap to 24-bit. */ 1304 1.23 nathanw TGAWREG(dc, TGA_REG_GOPR, 0x3 | (0x3 << 8)); 1305 1.23 nathanw 1306 1.23 nathanw /* Set which pixels we're drawing (of a possible 32). */ 1307 1.23 nathanw TGAWREG(dc, TGA_REG_GDAR, 0xffffffff); 1308 1.23 nathanw 1309 1.23 nathanw /* Set drawing mode to block fill. */ 1310 1.23 nathanw TGAWREG(dc, TGA_REG_GMOR, 0x2d); 1311 1.60 perry 1312 1.23 nathanw /* Insert write barrier before actually sending data */ 1313 1.23 nathanw /* XXX Abuses the fact that there is only one write barrier on Alphas */ 1314 1.23 nathanw TGAREGWB(dc, TGA_REG_GMOR, 1); 1315 1.23 nathanw 1316 1.23 nathanw while (lines--) { 1317 1.23 nathanw *rp = pixels; 1318 1.77 tsutsui rp = (int32_t *)((uint8_t *)rp + ri->ri_stride); 1319 1.23 nathanw } 1320 1.23 nathanw 1321 1.89 andvar /* Set graphics mode back to normal. */ 1322 1.23 nathanw TGAWREG(dc, TGA_REG_GMOR, 0); 1323 1.23 nathanw } 1324 1.23 nathanw 1325 1.23 nathanw static void 1326 1.71 dsl tga_erasecols (void *c, int row, int col, int num, long attr) 1327 1.23 nathanw { 1328 1.23 nathanw struct rasops_info *ri = c; 1329 1.23 nathanw struct tga_devconfig *dc = ri->ri_hw; 1330 1.23 nathanw int32_t color, lines, pixels; 1331 1.23 nathanw int32_t *rp; 1332 1.23 nathanw 1333 1.23 nathanw color = ri->ri_devcmap[(attr >> 16) & 15]; 1334 1.23 nathanw rp = (int32_t *)(ri->ri_bits + row*ri->ri_yscale + col*ri->ri_xscale); 1335 1.23 nathanw lines = ri->ri_font->fontheight; 1336 1.23 nathanw pixels = (num * ri->ri_font->fontwidth) - 1; 1337 1.23 nathanw 1338 1.23 nathanw /* Set fill color in block-color registers */ 1339 1.23 nathanw TGAWREG(dc, TGA_REG_GBCR0, color); 1340 1.23 nathanw TGAWREG(dc, TGA_REG_GBCR1, color); 1341 1.23 nathanw if (ri->ri_depth != 8) { 1342 1.23 nathanw TGAWREG(dc, TGA_REG_GBCR2, color); 1343 1.23 nathanw TGAWREG(dc, TGA_REG_GBCR3, color); 1344 1.23 nathanw TGAWREG(dc, TGA_REG_GBCR4, color); 1345 1.23 nathanw TGAWREG(dc, TGA_REG_GBCR5, color); 1346 1.23 nathanw TGAWREG(dc, TGA_REG_GBCR6, color); 1347 1.23 nathanw TGAWREG(dc, TGA_REG_GBCR7, color); 1348 1.23 nathanw } 1349 1.23 nathanw 1350 1.23 nathanw /* Set raster operation to "copy"... */ 1351 1.23 nathanw if (ri->ri_depth == 8) 1352 1.23 nathanw TGAWREG(dc, TGA_REG_GOPR, 0x3); 1353 1.23 nathanw else /* ... and in 24-bit mode, set the destination bitmap to 24-bit. */ 1354 1.23 nathanw TGAWREG(dc, TGA_REG_GOPR, 0x3 | (0x3 << 8)); 1355 1.23 nathanw 1356 1.23 nathanw /* Set which pixels we're drawing (of a possible 32). */ 1357 1.23 nathanw TGAWREG(dc, TGA_REG_GDAR, 0xffffffff); 1358 1.23 nathanw 1359 1.23 nathanw /* Set drawing mode to block fill. */ 1360 1.23 nathanw TGAWREG(dc, TGA_REG_GMOR, 0x2d); 1361 1.60 perry 1362 1.23 nathanw /* Insert write barrier before actually sending data */ 1363 1.23 nathanw /* XXX Abuses the fact that there is only one write barrier on Alphas */ 1364 1.23 nathanw TGAREGWB(dc, TGA_REG_GMOR, 1); 1365 1.23 nathanw 1366 1.23 nathanw while (lines--) { 1367 1.23 nathanw *rp = pixels; 1368 1.77 tsutsui rp = (int32_t *)((uint8_t *)rp + ri->ri_stride); 1369 1.23 nathanw } 1370 1.23 nathanw 1371 1.89 andvar /* Set graphics mode back to normal. */ 1372 1.23 nathanw TGAWREG(dc, TGA_REG_GMOR, 0); 1373 1.23 nathanw } 1374 1.23 nathanw 1375 1.17 elric 1376 1.22 nathanw static void 1377 1.77 tsutsui tga_ramdac_wr(void *v, u_int btreg, uint8_t val) 1378 1.17 elric { 1379 1.17 elric struct tga_devconfig *dc = v; 1380 1.17 elric 1381 1.17 elric if (btreg > BT485_REG_MAX) 1382 1.46 provos panic("tga_ramdac_wr: reg %d out of range", btreg); 1383 1.17 elric 1384 1.21 nathanw TGAWREG(dc, TGA_REG_EPDR, (btreg << 9) | (0 << 8 ) | val); /* XXX */ 1385 1.21 nathanw TGAREGWB(dc, TGA_REG_EPDR, 1); 1386 1.17 elric } 1387 1.17 elric 1388 1.22 nathanw static void 1389 1.77 tsutsui tga2_ramdac_wr(void *v, u_int btreg, uint8_t val) 1390 1.17 elric { 1391 1.17 elric struct tga_devconfig *dc = v; 1392 1.21 nathanw bus_space_handle_t ramdac; 1393 1.17 elric 1394 1.17 elric if (btreg > BT485_REG_MAX) 1395 1.46 provos panic("tga_ramdac_wr: reg %d out of range", btreg); 1396 1.17 elric 1397 1.77 tsutsui bus_space_subregion(dc->dc_memt, dc->dc_memh, 1398 1.77 tsutsui TGA2_MEM_RAMDAC + (0xe << 12) + (btreg << 8), 4, &ramdac); 1399 1.21 nathanw bus_space_write_4(dc->dc_memt, ramdac, 0, val & 0xff); 1400 1.21 nathanw bus_space_barrier(dc->dc_memt, ramdac, 0, 4, BUS_SPACE_BARRIER_WRITE); 1401 1.17 elric } 1402 1.17 elric 1403 1.77 tsutsui static uint8_t 1404 1.70 dsl tga_bt463_rd(void *v, u_int btreg) 1405 1.22 nathanw { 1406 1.22 nathanw struct tga_devconfig *dc = v; 1407 1.22 nathanw tga_reg_t rdval; 1408 1.22 nathanw 1409 1.60 perry /* 1410 1.60 perry * Strobe CE# (high->low->high) since status and data are latched on 1411 1.93 andvar * the falling and rising edges (respectively) of this active-low 1412 1.77 tsutsui * signal. 1413 1.22 nathanw */ 1414 1.60 perry 1415 1.22 nathanw TGAREGWB(dc, TGA_REG_EPSR, 1); 1416 1.22 nathanw TGAWREG(dc, TGA_REG_EPSR, (btreg << 2) | 2 | 1); 1417 1.22 nathanw TGAREGWB(dc, TGA_REG_EPSR, 1); 1418 1.22 nathanw TGAWREG(dc, TGA_REG_EPSR, (btreg << 2) | 2 | 0); 1419 1.22 nathanw 1420 1.22 nathanw TGAREGRB(dc, TGA_REG_EPSR, 1); 1421 1.22 nathanw 1422 1.22 nathanw rdval = TGARREG(dc, TGA_REG_EPDR); 1423 1.22 nathanw TGAREGWB(dc, TGA_REG_EPSR, 1); 1424 1.22 nathanw TGAWREG(dc, TGA_REG_EPSR, (btreg << 2) | 2 | 1); 1425 1.22 nathanw 1426 1.22 nathanw return (rdval >> 16) & 0xff; 1427 1.22 nathanw } 1428 1.22 nathanw 1429 1.22 nathanw static void 1430 1.77 tsutsui tga_bt463_wr(void *v, u_int btreg, uint8_t val) 1431 1.22 nathanw { 1432 1.22 nathanw struct tga_devconfig *dc = v; 1433 1.22 nathanw 1434 1.60 perry /* 1435 1.22 nathanw * In spite of the 21030 documentation, to set the MPU bus bits for 1436 1.22 nathanw * a write, you set them in the upper bits of EPDR, not EPSR. 1437 1.22 nathanw */ 1438 1.60 perry 1439 1.60 perry /* 1440 1.22 nathanw * Strobe CE# (high->low->high) since status and data are latched on 1441 1.22 nathanw * the falling and rising edges of this active-low signal. 1442 1.22 nathanw */ 1443 1.22 nathanw 1444 1.22 nathanw TGAREGWB(dc, TGA_REG_EPDR, 1); 1445 1.22 nathanw TGAWREG(dc, TGA_REG_EPDR, (btreg << 10) | 0x100 | val); 1446 1.22 nathanw TGAREGWB(dc, TGA_REG_EPDR, 1); 1447 1.22 nathanw TGAWREG(dc, TGA_REG_EPDR, (btreg << 10) | 0x000 | val); 1448 1.22 nathanw TGAREGWB(dc, TGA_REG_EPDR, 1); 1449 1.22 nathanw TGAWREG(dc, TGA_REG_EPDR, (btreg << 10) | 0x100 | val); 1450 1.22 nathanw } 1451 1.22 nathanw 1452 1.77 tsutsui static uint8_t 1453 1.70 dsl tga_ramdac_rd(void *v, u_int btreg) 1454 1.17 elric { 1455 1.17 elric struct tga_devconfig *dc = v; 1456 1.17 elric tga_reg_t rdval; 1457 1.17 elric 1458 1.17 elric if (btreg > BT485_REG_MAX) 1459 1.46 provos panic("tga_ramdac_rd: reg %d out of range", btreg); 1460 1.17 elric 1461 1.21 nathanw TGAWREG(dc, TGA_REG_EPSR, (btreg << 1) | 0x1); /* XXX */ 1462 1.21 nathanw TGAREGWB(dc, TGA_REG_EPSR, 1); 1463 1.17 elric 1464 1.21 nathanw rdval = TGARREG(dc, TGA_REG_EPDR); 1465 1.17 elric return (rdval >> 16) & 0xff; /* XXX */ 1466 1.17 elric } 1467 1.17 elric 1468 1.77 tsutsui static uint8_t 1469 1.70 dsl tga2_ramdac_rd(void *v, u_int btreg) 1470 1.17 elric { 1471 1.17 elric struct tga_devconfig *dc = v; 1472 1.21 nathanw bus_space_handle_t ramdac; 1473 1.77 tsutsui uint8_t retval; 1474 1.17 elric 1475 1.17 elric if (btreg > BT485_REG_MAX) 1476 1.46 provos panic("tga_ramdac_rd: reg %d out of range", btreg); 1477 1.17 elric 1478 1.77 tsutsui bus_space_subregion(dc->dc_memt, dc->dc_memh, 1479 1.77 tsutsui TGA2_MEM_RAMDAC + (0xe << 12) + (btreg << 8), 4, &ramdac); 1480 1.21 nathanw retval = bus_space_read_4(dc->dc_memt, ramdac, 0) & 0xff; 1481 1.21 nathanw bus_space_barrier(dc->dc_memt, ramdac, 0, 4, BUS_SPACE_BARRIER_READ); 1482 1.17 elric return retval; 1483 1.17 elric } 1484 1.17 elric 1485 1.17 elric #include <dev/ic/decmonitors.c> 1486 1.90 tsutsui static void tga2_ics9110_wr(struct tga_devconfig *dc, int dotclock); 1487 1.17 elric 1488 1.90 tsutsui static struct monitor *tga_getmonitor(struct tga_devconfig *dc); 1489 1.38 elric 1490 1.90 tsutsui static void 1491 1.70 dsl tga2_init(struct tga_devconfig *dc) 1492 1.17 elric { 1493 1.38 elric struct monitor *m = tga_getmonitor(dc); 1494 1.17 elric 1495 1.38 elric /* Deal with the dot clocks. 1496 1.38 elric */ 1497 1.38 elric if (dc->dc_tga_type == TGA_TYPE_POWERSTORM_4D20) { 1498 1.77 tsutsui /* 1499 1.77 tsutsui * Set this up as a reference clock for the 1500 1.38 elric * ibm561's PLL. 1501 1.38 elric */ 1502 1.38 elric tga2_ics9110_wr(dc, 14300000); 1503 1.77 tsutsui /* 1504 1.77 tsutsui * XXX Can't set up the dotclock properly, until such time 1505 1.38 elric * as the RAMDAC is configured. 1506 1.38 elric */ 1507 1.38 elric } else { 1508 1.38 elric /* otherwise the ics9110 is our clock. */ 1509 1.38 elric tga2_ics9110_wr(dc, m->dotclock); 1510 1.38 elric } 1511 1.21 nathanw #if 0 1512 1.60 perry TGAWREG(dc, TGA_REG_VHCR, 1513 1.77 tsutsui ((m->hbp / 4) << 21) | 1514 1.77 tsutsui ((m->hsync / 4) << 14) | 1515 1.38 elric (((m->hfp - 4) / 4) << 9) | 1516 1.77 tsutsui ((m->cols + 4) / 4)); 1517 1.17 elric #else 1518 1.60 perry TGAWREG(dc, TGA_REG_VHCR, 1519 1.77 tsutsui ((m->hbp / 4) << 21) | 1520 1.77 tsutsui ((m->hsync / 4) << 14) | 1521 1.38 elric (((m->hfp) / 4) << 9) | 1522 1.77 tsutsui ((m->cols) / 4)); 1523 1.17 elric #endif 1524 1.60 perry TGAWREG(dc, TGA_REG_VVCR, 1525 1.38 elric (m->vbp << 22) | 1526 1.38 elric (m->vsync << 16) | 1527 1.38 elric (m->vfp << 11) | 1528 1.38 elric (m->rows)); 1529 1.21 nathanw TGAWREG(dc, TGA_REG_VVBR, 1); 1530 1.21 nathanw TGAREGRWB(dc, TGA_REG_VHCR, 3); 1531 1.21 nathanw TGAWREG(dc, TGA_REG_VVVR, TGARREG(dc, TGA_REG_VVVR) | 1); 1532 1.21 nathanw TGAREGRWB(dc, TGA_REG_VVVR, 1); 1533 1.21 nathanw TGAWREG(dc, TGA_REG_GPMR, 0xffffffff); 1534 1.21 nathanw TGAREGRWB(dc, TGA_REG_GPMR, 1); 1535 1.17 elric } 1536 1.17 elric 1537 1.17 elric void 1538 1.70 dsl tga2_ics9110_wr(struct tga_devconfig *dc, int dotclock) 1539 1.17 elric { 1540 1.21 nathanw bus_space_handle_t clock; 1541 1.77 tsutsui uint32_t valU; 1542 1.17 elric int N, M, R, V, X; 1543 1.17 elric int i; 1544 1.17 elric 1545 1.17 elric switch (dotclock) { 1546 1.17 elric case 130808000: 1547 1.17 elric N = 0x40; M = 0x7; V = 0x0; X = 0x1; R = 0x1; break; 1548 1.17 elric case 119840000: 1549 1.17 elric N = 0x2d; M = 0x2b; V = 0x1; X = 0x1; R = 0x1; break; 1550 1.17 elric case 108180000: 1551 1.17 elric N = 0x11; M = 0x9; V = 0x1; X = 0x1; R = 0x2; break; 1552 1.17 elric case 103994000: 1553 1.17 elric N = 0x6d; M = 0xf; V = 0x0; X = 0x1; R = 0x1; break; 1554 1.17 elric case 175000000: 1555 1.17 elric N = 0x5F; M = 0x3E; V = 0x1; X = 0x1; R = 0x1; break; 1556 1.17 elric case 75000000: 1557 1.17 elric N = 0x6e; M = 0x15; V = 0x0; X = 0x1; R = 0x1; break; 1558 1.17 elric case 74000000: 1559 1.17 elric N = 0x2a; M = 0x41; V = 0x1; X = 0x1; R = 0x1; break; 1560 1.17 elric case 69000000: 1561 1.17 elric N = 0x35; M = 0xb; V = 0x0; X = 0x1; R = 0x1; break; 1562 1.17 elric case 65000000: 1563 1.17 elric N = 0x6d; M = 0x0c; V = 0x0; X = 0x1; R = 0x2; break; 1564 1.17 elric case 50000000: 1565 1.17 elric N = 0x37; M = 0x3f; V = 0x1; X = 0x1; R = 0x2; break; 1566 1.17 elric case 40000000: 1567 1.17 elric N = 0x5f; M = 0x11; V = 0x0; X = 0x1; R = 0x2; break; 1568 1.17 elric case 31500000: 1569 1.17 elric N = 0x16; M = 0x05; V = 0x0; X = 0x1; R = 0x2; break; 1570 1.17 elric case 25175000: 1571 1.17 elric N = 0x66; M = 0x1d; V = 0x0; X = 0x1; R = 0x2; break; 1572 1.17 elric case 135000000: 1573 1.17 elric N = 0x42; M = 0x07; V = 0x0; X = 0x1; R = 0x1; break; 1574 1.17 elric case 110000000: 1575 1.17 elric N = 0x60; M = 0x32; V = 0x1; X = 0x1; R = 0x2; break; 1576 1.17 elric case 202500000: 1577 1.17 elric N = 0x60; M = 0x32; V = 0x1; X = 0x1; R = 0x2; break; 1578 1.38 elric case 14300000: /* this one is just a ref clock */ 1579 1.38 elric N = 0x03; M = 0x03; V = 0x1; X = 0x1; R = 0x3; break; 1580 1.17 elric default: 1581 1.46 provos panic("unrecognized clock rate %d", dotclock); 1582 1.17 elric } 1583 1.17 elric 1584 1.17 elric /* XXX -- hard coded, bad */ 1585 1.77 tsutsui valU = N | ( M << 7 ) | (V << 14); 1586 1.17 elric valU |= (X << 15) | (R << 17); 1587 1.17 elric valU |= 0x17 << 19; 1588 1.17 elric 1589 1.21 nathanw bus_space_subregion(dc->dc_memt, dc->dc_memh, TGA2_MEM_EXTDEV + 1590 1.21 nathanw TGA2_MEM_CLOCK + (0xe << 12), 4, &clock); /* XXX */ 1591 1.17 elric 1592 1.77 tsutsui for (i = 24; i > 0; i--) { 1593 1.77 tsutsui uint32_t writeval; 1594 1.60 perry 1595 1.21 nathanw writeval = valU & 0x1; 1596 1.60 perry if (i == 1) 1597 1.60 perry writeval |= 0x2; 1598 1.21 nathanw valU >>= 1; 1599 1.21 nathanw bus_space_write_4(dc->dc_memt, clock, 0, writeval); 1600 1.77 tsutsui bus_space_barrier(dc->dc_memt, clock, 0, 4, 1601 1.77 tsutsui BUS_SPACE_BARRIER_WRITE); 1602 1.60 perry } 1603 1.21 nathanw bus_space_subregion(dc->dc_memt, dc->dc_memh, TGA2_MEM_EXTDEV + 1604 1.21 nathanw TGA2_MEM_CLOCK + (0xe << 12) + (0x1 << 11) + (0x1 << 11), 4, 1605 1.77 tsutsui &clock); /* XXX */ 1606 1.21 nathanw bus_space_write_4(dc->dc_memt, clock, 0, 0x0); 1607 1.21 nathanw bus_space_barrier(dc->dc_memt, clock, 0, 0, BUS_SPACE_BARRIER_WRITE); 1608 1.38 elric } 1609 1.38 elric 1610 1.90 tsutsui static struct monitor * 1611 1.70 dsl tga_getmonitor(struct tga_devconfig *dc) 1612 1.38 elric { 1613 1.77 tsutsui 1614 1.38 elric return &decmonitors[(~TGARREG(dc, TGA_REG_GREV) >> 16) & 0x0f]; 1615 1.38 elric } 1616 1.38 elric 1617 1.90 tsutsui static unsigned int 1618 1.70 dsl tga_getdotclock(struct tga_devconfig *dc) 1619 1.38 elric { 1620 1.77 tsutsui 1621 1.38 elric return tga_getmonitor(dc)->dotclock; 1622 1.1 drochner } 1623