1 /* $NetBSD: p9100.c,v 1.62 2014/07/25 08:10:38 dholland Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2005, 2006 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * color display (p9100) driver. 34 * 35 * Does not handle interrupts, even though they can occur. 36 * 37 * XXX should defer colormap updates to vertical retrace interrupts 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: p9100.c,v 1.62 2014/07/25 08:10:38 dholland Exp $"); 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/buf.h> 46 #include <sys/device.h> 47 #include <sys/ioctl.h> 48 #include <sys/malloc.h> 49 #include <sys/mman.h> 50 #include <sys/tty.h> 51 #include <sys/conf.h> 52 53 #include <sys/bus.h> 54 #include <machine/autoconf.h> 55 56 #include <dev/sun/fbio.h> 57 #include <dev/sun/fbvar.h> 58 #include <dev/sun/btreg.h> 59 #include <dev/sun/btvar.h> 60 61 #include <dev/sbus/p9100reg.h> 62 63 #include <dev/sbus/sbusvar.h> 64 65 #include <dev/wscons/wsdisplayvar.h> 66 #include <dev/wscons/wsconsio.h> 67 #include <dev/wsfont/wsfont.h> 68 #include <dev/rasops/rasops.h> 69 70 #include <dev/wscons/wsdisplay_vconsvar.h> 71 #include <dev/wscons/wsdisplay_glyphcachevar.h> 72 73 #include "opt_wsemul.h" 74 #include "rasops_glue.h" 75 #include "opt_pnozz.h" 76 77 #include "ioconf.h" 78 79 #include "tctrl.h" 80 #if NTCTRL > 0 81 #include <machine/tctrl.h> 82 #include <sparc/dev/tctrlvar.h> /*XXX*/ 83 #endif 84 85 #ifdef PNOZZ_DEBUG 86 #define DPRINTF aprint_normal 87 #else 88 #define DPRINTF while (0) aprint_normal 89 #endif 90 91 struct pnozz_cursor { 92 short pc_enable; /* cursor is enabled */ 93 struct fbcurpos pc_pos; /* position */ 94 struct fbcurpos pc_hot; /* hot-spot */ 95 struct fbcurpos pc_size; /* size of mask & image fields */ 96 uint32_t pc_bits[0x100]; /* space for mask & image bits */ 97 unsigned char red[3], green[3]; 98 unsigned char blue[3]; /* cursor palette */ 99 }; 100 101 /* per-display variables */ 102 struct p9100_softc { 103 device_t sc_dev; /* base device */ 104 struct fbdevice sc_fb; /* frame buffer device */ 105 106 bus_space_tag_t sc_bustag; 107 108 bus_addr_t sc_ctl_paddr; /* phys address description */ 109 bus_size_t sc_ctl_psize; /* for device mmap() */ 110 bus_space_handle_t sc_ctl_memh; /* bus space handle */ 111 112 bus_addr_t sc_fb_paddr; /* phys address description */ 113 bus_size_t sc_fb_psize; /* for device mmap() */ 114 #ifdef PNOZZ_USE_LATCH 115 bus_space_handle_t sc_fb_memh; /* bus space handle */ 116 #endif 117 uint32_t sc_mono_width; /* for setup_mono */ 118 119 uint32_t sc_width; 120 uint32_t sc_height; /* panel width / height */ 121 uint32_t sc_stride; 122 uint32_t sc_depth; 123 int sc_depthshift; /* blitter works on bytes not pixels */ 124 125 union bt_cmap sc_cmap; /* Brooktree color map */ 126 127 struct pnozz_cursor sc_cursor; 128 129 int sc_mode; 130 int sc_video, sc_powerstate; 131 uint32_t sc_bg; 132 volatile uint32_t sc_last_offset; 133 struct vcons_data vd; 134 uint8_t sc_dac_power; 135 glyphcache sc_gc; 136 }; 137 138 139 static struct vcons_screen p9100_console_screen; 140 141 extern const u_char rasops_cmap[768]; 142 143 struct wsscreen_descr p9100_defscreendesc = { 144 "default", 145 0, 0, 146 NULL, 147 8, 16, 148 WSSCREEN_WSCOLORS, 149 }; 150 151 const struct wsscreen_descr *_p9100_scrlist[] = { 152 &p9100_defscreendesc, 153 /* XXX other formats, graphics screen? */ 154 }; 155 156 struct wsscreen_list p9100_screenlist = { 157 sizeof(_p9100_scrlist) / sizeof(struct wsscreen_descr *), 158 _p9100_scrlist 159 }; 160 161 /* autoconfiguration driver */ 162 static int p9100_sbus_match(device_t, cfdata_t, void *); 163 static void p9100_sbus_attach(device_t, device_t, void *); 164 165 static void p9100unblank(device_t); 166 167 CFATTACH_DECL_NEW(pnozz, sizeof(struct p9100_softc), 168 p9100_sbus_match, p9100_sbus_attach, NULL, NULL); 169 170 static dev_type_open(p9100open); 171 static dev_type_close(p9100close); 172 static dev_type_ioctl(p9100ioctl); 173 static dev_type_mmap(p9100mmap); 174 175 const struct cdevsw pnozz_cdevsw = { 176 .d_open = p9100open, 177 .d_close = nullclose, 178 .d_read = noread, 179 .d_write = nowrite, 180 .d_ioctl = p9100ioctl, 181 .d_stop = nostop, 182 .d_tty = notty, 183 .d_poll = nopoll, 184 .d_mmap = p9100mmap, 185 .d_kqfilter = nokqfilter, 186 .d_discard = nodiscard, 187 .d_flag = 0 188 }; 189 190 /* frame buffer generic driver */ 191 static struct fbdriver p9100fbdriver = { 192 p9100unblank, p9100open, p9100close, p9100ioctl, nopoll, 193 p9100mmap, nokqfilter 194 }; 195 196 static void p9100loadcmap(struct p9100_softc *, int, int); 197 static void p9100_set_video(struct p9100_softc *, int); 198 static int p9100_get_video(struct p9100_softc *); 199 static uint32_t p9100_ctl_read_4(struct p9100_softc *, bus_size_t); 200 static void p9100_ctl_write_4(struct p9100_softc *, bus_size_t, uint32_t); 201 static uint8_t p9100_ramdac_read(struct p9100_softc *, bus_size_t); 202 static void p9100_ramdac_write(struct p9100_softc *, bus_size_t, uint8_t); 203 204 static uint8_t p9100_ramdac_read_ctl(struct p9100_softc *, int); 205 static void p9100_ramdac_write_ctl(struct p9100_softc *, int, uint8_t); 206 207 static void p9100_init_engine(struct p9100_softc *); 208 static int p9100_set_depth(struct p9100_softc *, int); 209 210 #if NWSDISPLAY > 0 211 static void p9100_sync(struct p9100_softc *); 212 static void p9100_bitblt(void *, int, int, int, int, int, int, int); 213 static void p9100_rectfill(void *, int, int, int, int, uint32_t); 214 static void p9100_clearscreen(struct p9100_softc *); 215 216 static void p9100_setup_mono(struct p9100_softc *, int, int, int, int, 217 uint32_t, uint32_t); 218 static void p9100_feed_line(struct p9100_softc *, int, uint8_t *); 219 static void p9100_set_color_reg(struct p9100_softc *, int, int32_t); 220 221 static void p9100_copycols(void *, int, int, int, int); 222 static void p9100_erasecols(void *, int, int, int, long); 223 static void p9100_copyrows(void *, int, int, int); 224 static void p9100_eraserows(void *, int, int, long); 225 /*static int p9100_mapchar(void *, int, u_int *);*/ 226 static void p9100_putchar(void *, int, int, u_int, long); 227 static void p9100_putchar_aa(void *, int, int, u_int, long); 228 static void p9100_cursor(void *, int, int, int); 229 230 static int p9100_putcmap(struct p9100_softc *, struct wsdisplay_cmap *); 231 static int p9100_getcmap(struct p9100_softc *, struct wsdisplay_cmap *); 232 static int p9100_ioctl(void *, void *, u_long, void *, int, struct lwp *); 233 static paddr_t p9100_mmap(void *, void *, off_t, int); 234 235 /*static int p9100_load_font(void *, void *, struct wsdisplay_font *);*/ 236 237 static void p9100_init_screen(void *, struct vcons_screen *, int, 238 long *); 239 #endif 240 241 static void p9100_init_cursor(struct p9100_softc *); 242 243 static void p9100_set_fbcursor(struct p9100_softc *); 244 static void p9100_setcursorcmap(struct p9100_softc *); 245 static void p9100_loadcursor(struct p9100_softc *); 246 247 #if 0 248 static int p9100_intr(void *); 249 #endif 250 251 /* power management stuff */ 252 static bool p9100_suspend(device_t, const pmf_qual_t *); 253 static bool p9100_resume(device_t, const pmf_qual_t *); 254 255 #if NTCTRL > 0 256 static void p9100_set_extvga(void *, int); 257 #endif 258 259 #if NWSDISPLAY > 0 260 struct wsdisplay_accessops p9100_accessops = { 261 p9100_ioctl, 262 p9100_mmap, 263 NULL, /* vcons_alloc_screen */ 264 NULL, /* vcons_free_screen */ 265 NULL, /* vcons_show_screen */ 266 NULL, /* load_font */ 267 NULL, /* polls */ 268 NULL, /* scroll */ 269 }; 270 #endif 271 272 #ifdef PNOZZ_USE_LATCH 273 #define PNOZZ_LATCH(sc, off) if(sc->sc_last_offset != (off & 0xffffff80)) { \ 274 (void)bus_space_read_4(sc->sc_bustag, sc->sc_fb_memh, off); \ 275 sc->sc_last_offset = off & 0xffffff80; } 276 #else 277 #define PNOZZ_LATCH(a, b) 278 #endif 279 280 /* 281 * Match a p9100. 282 */ 283 static int 284 p9100_sbus_match(device_t parent, cfdata_t cf, void *aux) 285 { 286 struct sbus_attach_args *sa = aux; 287 288 if (strcmp("p9100", sa->sa_name) == 0) 289 return 100; 290 return 0; 291 } 292 293 294 /* 295 * Attach a display. We need to notice if it is the console, too. 296 */ 297 static void 298 p9100_sbus_attach(device_t parent, device_t self, void *args) 299 { 300 struct p9100_softc *sc = device_private(self); 301 struct sbus_attach_args *sa = args; 302 struct fbdevice *fb = &sc->sc_fb; 303 int isconsole; 304 int node = sa->sa_node; 305 int i, j; 306 uint8_t ver, cmap[768]; 307 308 #if NWSDISPLAY > 0 309 struct wsemuldisplaydev_attach_args aa; 310 struct rasops_info *ri; 311 unsigned long defattr; 312 #endif 313 314 sc->sc_last_offset = 0xffffffff; 315 sc->sc_dev = self; 316 317 /* 318 * When the ROM has mapped in a p9100 display, the address 319 * maps only the video RAM, so in any case we have to map the 320 * registers ourselves. 321 */ 322 323 if (sa->sa_npromvaddrs != 0) 324 fb->fb_pixels = (void *)sa->sa_promvaddrs[0]; 325 326 /* Remember cookies for p9100_mmap() */ 327 sc->sc_bustag = sa->sa_bustag; 328 329 sc->sc_ctl_paddr = sbus_bus_addr(sa->sa_bustag, 330 sa->sa_reg[0].oa_space, sa->sa_reg[0].oa_base); 331 sc->sc_ctl_psize = 0x8000;/*(bus_size_t)sa->sa_reg[0].oa_size;*/ 332 333 sc->sc_fb_paddr = sbus_bus_addr(sa->sa_bustag, 334 sa->sa_reg[2].oa_space, sa->sa_reg[2].oa_base); 335 sc->sc_fb_psize = (bus_size_t)sa->sa_reg[2].oa_size; 336 337 if (sbus_bus_map(sc->sc_bustag, 338 sa->sa_reg[0].oa_space, 339 sa->sa_reg[0].oa_base, 340 /* 341 * XXX for some reason the SBus resources don't cover 342 * all registers, so we just map what we need 343 */ 344 0x8000, 345 0, &sc->sc_ctl_memh) != 0) { 346 printf("%s: cannot map control registers\n", 347 device_xname(self)); 348 return; 349 } 350 351 /* 352 * we need to map the framebuffer even though we never write to it, 353 * thanks to some weirdness in the SPARCbook's SBus glue for the 354 * P9100 - all register accesses need to be 'latched in' whenever we 355 * go to another 0x80 aligned 'page' by reading the framebuffer at the 356 * same offset 357 * XXX apparently the latter isn't true - my SP3GX works fine without 358 */ 359 #ifdef PNOZZ_USE_LATCH 360 if (fb->fb_pixels == NULL) { 361 if (sbus_bus_map(sc->sc_bustag, 362 sa->sa_reg[2].oa_space, 363 sa->sa_reg[2].oa_base, 364 sc->sc_fb_psize, 365 BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_LARGE, 366 &sc->sc_fb_memh) != 0) { 367 printf("%s: cannot map framebuffer\n", 368 device_xname(self)); 369 return; 370 } 371 fb->fb_pixels = (char *)sc->sc_fb_memh; 372 } else { 373 sc->sc_fb_memh = (bus_space_handle_t) fb->fb_pixels; 374 } 375 #endif 376 sc->sc_width = prom_getpropint(node, "width", 800); 377 sc->sc_height = prom_getpropint(node, "height", 600); 378 sc->sc_depth = prom_getpropint(node, "depth", 8) >> 3; 379 380 sc->sc_stride = prom_getpropint(node, "linebytes", 381 sc->sc_width * sc->sc_depth); 382 383 fb->fb_driver = &p9100fbdriver; 384 fb->fb_device = sc->sc_dev; 385 fb->fb_flags = device_cfdata(sc->sc_dev)->cf_flags & FB_USERMASK; 386 #ifdef PNOZZ_EMUL_CG3 387 fb->fb_type.fb_type = FBTYPE_SUN3COLOR; 388 #else 389 fb->fb_type.fb_type = FBTYPE_P9100; 390 #endif 391 fb->fb_pixels = NULL; 392 393 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 394 395 isconsole = fb_is_console(node); 396 #if 0 397 if (!isconsole) { 398 aprint_normal("\n"); 399 aprint_error_dev(self, "fatal error: PROM didn't configure device\n"); 400 return; 401 } 402 #endif 403 404 fb->fb_type.fb_depth = 8; 405 sc->sc_depth = 1; 406 sc->sc_depthshift = 0; 407 408 /* check the RAMDAC */ 409 ver = p9100_ramdac_read_ctl(sc, DAC_VERSION); 410 411 p9100_init_engine(sc); 412 p9100_set_depth(sc, 8); 413 414 fb_setsize_obp(fb, fb->fb_type.fb_depth, sc->sc_width, sc->sc_height, 415 node); 416 417 #if 0 418 bus_intr_establish(sc->sc_bustag, sa->sa_pri, IPL_BIO, 419 p9100_intr, sc); 420 #endif 421 422 fb->fb_type.fb_cmsize = prom_getpropint(node, "cmsize", 256); 423 if ((1 << fb->fb_type.fb_depth) != fb->fb_type.fb_cmsize) 424 printf(", %d entry colormap", fb->fb_type.fb_cmsize); 425 426 /* make sure we are not blanked */ 427 if (isconsole) 428 p9100_set_video(sc, 1); 429 430 /* register with power management */ 431 sc->sc_video = 1; 432 sc->sc_powerstate = PWR_RESUME; 433 if (!pmf_device_register(self, p9100_suspend, p9100_resume)) { 434 panic("%s: could not register with PMF", 435 device_xname(sc->sc_dev)); 436 } 437 438 if (isconsole) { 439 printf(" (console)\n"); 440 #ifdef RASTERCONSOLE 441 /*p9100loadcmap(sc, 255, 1);*/ 442 fbrcons_init(fb); 443 #endif 444 } else 445 printf("\n"); 446 447 #if NWSDISPLAY > 0 448 wsfont_init(); 449 450 #ifdef PNOZZ_DEBUG 451 /* make the glyph cache visible */ 452 sc->sc_height -= 100; 453 #endif 454 455 sc->sc_gc.gc_bitblt = p9100_bitblt; 456 sc->sc_gc.gc_blitcookie = sc; 457 sc->sc_gc.gc_rop = ROP_SRC; 458 459 vcons_init(&sc->vd, sc, &p9100_defscreendesc, &p9100_accessops); 460 sc->vd.init_screen = p9100_init_screen; 461 462 vcons_init_screen(&sc->vd, &p9100_console_screen, 1, &defattr); 463 p9100_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC; 464 465 /* Initialize the default color map. */ 466 rasops_get_cmap(&p9100_console_screen.scr_ri, cmap, 768); 467 468 j = 0; 469 for (i = 0; i < 256; i++) { 470 sc->sc_cmap.cm_map[i][0] = cmap[j]; 471 j++; 472 sc->sc_cmap.cm_map[i][1] = cmap[j]; 473 j++; 474 sc->sc_cmap.cm_map[i][2] = cmap[j]; 475 j++; 476 } 477 p9100loadcmap(sc, 0, 256); 478 479 sc->sc_bg = (defattr >> 16) & 0xff; 480 p9100_clearscreen(sc); 481 482 ri = &p9100_console_screen.scr_ri; 483 484 p9100_defscreendesc.nrows = ri->ri_rows; 485 p9100_defscreendesc.ncols = ri->ri_cols; 486 p9100_defscreendesc.textops = &ri->ri_ops; 487 p9100_defscreendesc.capabilities = ri->ri_caps; 488 489 glyphcache_init(&sc->sc_gc, sc->sc_height + 5, 490 (0x200000 / sc->sc_stride) - sc->sc_height - 5, 491 sc->sc_width, 492 ri->ri_font->fontwidth, 493 ri->ri_font->fontheight, 494 defattr); 495 496 if(isconsole) { 497 wsdisplay_cnattach(&p9100_defscreendesc, ri, 0, 0, defattr); 498 vcons_replay_msgbuf(&p9100_console_screen); 499 } 500 501 aa.console = isconsole; 502 aa.scrdata = &p9100_screenlist; 503 aa.accessops = &p9100_accessops; 504 aa.accesscookie = &sc->vd; 505 506 config_found(self, &aa, wsemuldisplaydevprint); 507 #endif 508 fb->fb_type.fb_size = fb->fb_type.fb_height * fb->fb_linebytes; 509 printf("%s: rev %d / %x, %dx%d, depth %d mem %x\n", 510 device_xname(self), 511 (i & 7), ver, fb->fb_type.fb_width, fb->fb_type.fb_height, 512 fb->fb_type.fb_depth, (unsigned int)sc->sc_fb_psize); 513 /* cursor sprite handling */ 514 p9100_init_cursor(sc); 515 516 /* attach the fb */ 517 fb_attach(fb, isconsole); 518 519 #if NTCTRL > 0 520 /* register callback for external monitor status change */ 521 tadpole_register_callback(p9100_set_extvga, sc); 522 #endif 523 } 524 525 int 526 p9100open(dev_t dev, int flags, int mode, struct lwp *l) 527 { 528 int unit = minor(dev); 529 530 if (device_lookup(&pnozz_cd, unit) == NULL) 531 return (ENXIO); 532 return (0); 533 } 534 535 int 536 p9100close(dev_t dev, int flags, int mode, struct lwp *l) 537 { 538 struct p9100_softc *sc = device_lookup_private(&pnozz_cd, minor(dev)); 539 540 #if NWSDISPLAY > 0 541 p9100_init_engine(sc); 542 p9100_set_depth(sc, 8); 543 p9100loadcmap(sc, 0, 256); 544 p9100_clearscreen(sc); 545 glyphcache_wipe(&sc->sc_gc); 546 vcons_redraw_screen(sc->vd.active); 547 #endif 548 return 0; 549 } 550 551 int 552 p9100ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) 553 { 554 struct p9100_softc *sc = device_lookup_private(&pnozz_cd, minor(dev)); 555 struct fbgattr *fba; 556 int error, v; 557 558 switch (cmd) { 559 560 case FBIOGTYPE: 561 *(struct fbtype *)data = sc->sc_fb.fb_type; 562 break; 563 564 case FBIOGATTR: 565 fba = (struct fbgattr *)data; 566 fba->real_type = sc->sc_fb.fb_type.fb_type; 567 fba->owner = 0; /* XXX ??? */ 568 fba->fbtype = sc->sc_fb.fb_type; 569 fba->sattr.flags = 0; 570 fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; 571 fba->sattr.dev_specific[0] = -1; 572 fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; 573 fba->emu_types[1] = -1; 574 break; 575 576 case FBIOGETCMAP: 577 #define p ((struct fbcmap *)data) 578 return (bt_getcmap(p, &sc->sc_cmap, 256, 1)); 579 580 case FBIOPUTCMAP: 581 /* copy to software map */ 582 error = bt_putcmap(p, &sc->sc_cmap, 256, 1); 583 if (error) 584 return (error); 585 /* now blast them into the chip */ 586 /* XXX should use retrace interrupt */ 587 p9100loadcmap(sc, p->index, p->count); 588 #undef p 589 break; 590 591 case FBIOGVIDEO: 592 *(int *)data = p9100_get_video(sc); 593 break; 594 595 case FBIOSVIDEO: 596 p9100_set_video(sc, *(int *)data); 597 break; 598 599 /* these are for both FBIOSCURSOR and FBIOGCURSOR */ 600 #define p ((struct fbcursor *)data) 601 #define pc (&sc->sc_cursor) 602 603 case FBIOGCURSOR: 604 p->set = FB_CUR_SETALL; /* close enough, anyway */ 605 p->enable = pc->pc_enable; 606 p->pos = pc->pc_pos; 607 p->hot = pc->pc_hot; 608 p->size = pc->pc_size; 609 610 if (p->image != NULL) { 611 error = copyout(pc->pc_bits, p->image, 0x200); 612 if (error) 613 return error; 614 error = copyout(&pc->pc_bits[0x80], p->mask, 0x200); 615 if (error) 616 return error; 617 } 618 619 p->cmap.index = 0; 620 p->cmap.count = 3; 621 if (p->cmap.red != NULL) { 622 copyout(pc->red, p->cmap.red, 3); 623 copyout(pc->green, p->cmap.green, 3); 624 copyout(pc->blue, p->cmap.blue, 3); 625 } 626 break; 627 628 case FBIOSCURSOR: 629 { 630 int count; 631 uint32_t image[0x80], mask[0x80]; 632 uint8_t red[3], green[3], blue[3]; 633 634 v = p->set; 635 if (v & FB_CUR_SETCMAP) { 636 error = copyin(p->cmap.red, red, 3); 637 error |= copyin(p->cmap.green, green, 3); 638 error |= copyin(p->cmap.blue, blue, 3); 639 if (error) 640 return error; 641 } 642 if (v & FB_CUR_SETSHAPE) { 643 if (p->size.x > 64 || p->size.y > 64) 644 return EINVAL; 645 memset(&mask, 0, 0x200); 646 memset(&image, 0, 0x200); 647 count = p->size.y * 8; 648 error = copyin(p->image, image, count); 649 if (error) 650 return error; 651 error = copyin(p->mask, mask, count); 652 if (error) 653 return error; 654 } 655 656 /* parameters are OK; do it */ 657 if (v & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)) { 658 if (v & FB_CUR_SETCUR) 659 pc->pc_enable = p->enable; 660 if (v & FB_CUR_SETPOS) 661 pc->pc_pos = p->pos; 662 if (v & FB_CUR_SETHOT) 663 pc->pc_hot = p->hot; 664 p9100_set_fbcursor(sc); 665 } 666 667 if (v & FB_CUR_SETCMAP) { 668 memcpy(pc->red, red, 3); 669 memcpy(pc->green, green, 3); 670 memcpy(pc->blue, blue, 3); 671 p9100_setcursorcmap(sc); 672 } 673 674 if (v & FB_CUR_SETSHAPE) { 675 memcpy(pc->pc_bits, image, 0x200); 676 memcpy(&pc->pc_bits[0x80], mask, 0x200); 677 p9100_loadcursor(sc); 678 } 679 } 680 break; 681 682 #undef p 683 #undef cc 684 685 case FBIOGCURPOS: 686 *(struct fbcurpos *)data = sc->sc_cursor.pc_pos; 687 break; 688 689 case FBIOSCURPOS: 690 sc->sc_cursor.pc_pos = *(struct fbcurpos *)data; 691 p9100_set_fbcursor(sc); 692 break; 693 694 case FBIOGCURMAX: 695 /* max cursor size is 64x64 */ 696 ((struct fbcurpos *)data)->x = 64; 697 ((struct fbcurpos *)data)->y = 64; 698 break; 699 700 default: 701 return (ENOTTY); 702 } 703 return (0); 704 } 705 706 static uint32_t 707 p9100_ctl_read_4(struct p9100_softc *sc, bus_size_t off) 708 { 709 710 PNOZZ_LATCH(sc, off); 711 return bus_space_read_4(sc->sc_bustag, sc->sc_ctl_memh, off); 712 } 713 714 static void 715 p9100_ctl_write_4(struct p9100_softc *sc, bus_size_t off, uint32_t v) 716 { 717 718 PNOZZ_LATCH(sc, off); 719 bus_space_write_4(sc->sc_bustag, sc->sc_ctl_memh, off, v); 720 } 721 722 /* initialize the drawing engine */ 723 static void 724 p9100_init_engine(struct p9100_softc *sc) 725 { 726 /* reset clipping rectangles */ 727 uint32_t rmax = ((sc->sc_width & 0x3fff) << 16) | 728 (sc->sc_height & 0x3fff); 729 730 sc->sc_last_offset = 0xffffffff; 731 732 p9100_ctl_write_4(sc, WINDOW_OFFSET, 0); 733 p9100_ctl_write_4(sc, WINDOW_MIN, 0); 734 p9100_ctl_write_4(sc, WINDOW_MAX, rmax); 735 p9100_ctl_write_4(sc, BYTE_CLIP_MIN, 0); 736 p9100_ctl_write_4(sc, BYTE_CLIP_MAX, 0x3fff3fff); 737 p9100_ctl_write_4(sc, DRAW_MODE, 0); 738 p9100_ctl_write_4(sc, PLANE_MASK, 0xffffffff); 739 p9100_ctl_write_4(sc, PATTERN0, 0xffffffff); 740 p9100_ctl_write_4(sc, PATTERN1, 0xffffffff); 741 p9100_ctl_write_4(sc, PATTERN2, 0xffffffff); 742 p9100_ctl_write_4(sc, PATTERN3, 0xffffffff); 743 744 } 745 746 /* we only need these in the wsdisplay case */ 747 #if NWSDISPLAY > 0 748 749 /* wait until the engine is idle */ 750 static void 751 p9100_sync(struct p9100_softc *sc) 752 { 753 while((p9100_ctl_read_4(sc, ENGINE_STATUS) & 754 (ENGINE_BUSY | BLITTER_BUSY)) != 0); 755 } 756 757 static void 758 p9100_set_color_reg(struct p9100_softc *sc, int reg, int32_t col) 759 { 760 uint32_t out; 761 762 switch(sc->sc_depth) 763 { 764 case 1: /* 8 bit */ 765 out = (col << 8) | col; 766 out |= out << 16; 767 break; 768 case 2: /* 16 bit */ 769 out = col | (col << 16); 770 break; 771 default: 772 out = col; 773 } 774 p9100_ctl_write_4(sc, reg, out); 775 } 776 777 /* screen-to-screen blit */ 778 static void 779 p9100_bitblt(void *cookie, int xs, int ys, int xd, int yd, int wi, 780 int he, int rop) 781 { 782 struct p9100_softc *sc = cookie; 783 uint32_t src, dst, srcw, dstw; 784 785 sc->sc_last_offset = 0xffffffff; 786 787 src = ((xs & 0x3fff) << 16) | (ys & 0x3fff); 788 dst = ((xd & 0x3fff) << 16) | (yd & 0x3fff); 789 srcw = (((xs + wi - 1) & 0x3fff) << 16) | ((ys + he - 1) & 0x3fff); 790 dstw = (((xd + wi - 1) & 0x3fff) << 16) | ((yd + he - 1) & 0x3fff); 791 792 p9100_sync(sc); 793 794 p9100_ctl_write_4(sc, RASTER_OP, rop); 795 p9100_ctl_write_4(sc, BYTE_CLIP_MAX, 0x3fff3fff); 796 797 p9100_ctl_write_4(sc, ABS_XY0, src << sc->sc_depthshift); 798 p9100_ctl_write_4(sc, ABS_XY1, srcw << sc->sc_depthshift); 799 p9100_ctl_write_4(sc, ABS_XY2, dst << sc->sc_depthshift); 800 p9100_ctl_write_4(sc, ABS_XY3, dstw << sc->sc_depthshift); 801 802 (void)p9100_ctl_read_4(sc, COMMAND_BLIT); 803 } 804 805 /* solid rectangle fill */ 806 static void 807 p9100_rectfill(void *cookie, int xs, int ys, int wi, int he, uint32_t col) 808 { 809 struct p9100_softc *sc = cookie; 810 uint32_t src, srcw; 811 812 sc->sc_last_offset = 0xffffffff; 813 814 src = ((xs & 0x3fff) << 16) | (ys & 0x3fff); 815 srcw = (((xs + wi) & 0x3fff) << 16) | ((ys + he) & 0x3fff); 816 p9100_sync(sc); 817 p9100_ctl_write_4(sc, BYTE_CLIP_MAX, 0x3fff3fff); 818 p9100_set_color_reg(sc, FOREGROUND_COLOR, col); 819 p9100_set_color_reg(sc, BACKGROUND_COLOR, col); 820 p9100_ctl_write_4(sc, RASTER_OP, ROP_PAT); 821 p9100_ctl_write_4(sc, COORD_INDEX, 0); 822 p9100_ctl_write_4(sc, RECT_RTW_XY, src); 823 p9100_ctl_write_4(sc, RECT_RTW_XY, srcw); 824 (void)p9100_ctl_read_4(sc, COMMAND_QUAD); 825 } 826 827 /* setup for mono->colour expansion */ 828 static void 829 p9100_setup_mono(struct p9100_softc *sc, int x, int y, int wi, int he, 830 uint32_t fg, uint32_t bg) 831 { 832 833 sc->sc_last_offset = 0xffffffff; 834 835 p9100_sync(sc); 836 /* 837 * this doesn't make any sense to me either, but for some reason the 838 * chip applies the foreground colour to 0 pixels 839 */ 840 841 p9100_set_color_reg(sc,FOREGROUND_COLOR,bg); 842 p9100_set_color_reg(sc,BACKGROUND_COLOR,fg); 843 844 p9100_ctl_write_4(sc, BYTE_CLIP_MAX, 0x3fff3fff); 845 p9100_ctl_write_4(sc, RASTER_OP, ROP_SRC); 846 p9100_ctl_write_4(sc, ABS_X0, x); 847 p9100_ctl_write_4(sc, ABS_XY1, (x << 16) | (y & 0xFFFFL)); 848 p9100_ctl_write_4(sc, ABS_X2, (x + wi)); 849 p9100_ctl_write_4(sc, ABS_Y3, he); 850 /* now feed the data into the chip */ 851 sc->sc_mono_width = wi; 852 } 853 854 /* write monochrome data to the screen through the blitter */ 855 static void 856 p9100_feed_line(struct p9100_softc *sc, int count, uint8_t *data) 857 { 858 int i; 859 uint32_t latch = 0, bork; 860 int shift = 24; 861 int to_go = sc->sc_mono_width; 862 863 PNOZZ_LATCH(sc, PIXEL_1); 864 865 for (i = 0; i < count; i++) { 866 bork = data[i]; 867 latch |= (bork << shift); 868 if (shift == 0) { 869 /* check how many bits are significant */ 870 if (to_go > 31) { 871 bus_space_write_4(sc->sc_bustag, 872 sc->sc_ctl_memh, 873 (PIXEL_1 + (31 << 2)), latch); 874 to_go -= 32; 875 } else 876 { 877 bus_space_write_4(sc->sc_bustag, 878 sc->sc_ctl_memh, 879 (PIXEL_1 + ((to_go - 1) << 2)), latch); 880 to_go = 0; 881 } 882 latch = 0; 883 shift = 24; 884 } else 885 shift -= 8; 886 } 887 if (shift != 24) 888 p9100_ctl_write_4(sc, (PIXEL_1 + ((to_go - 1) << 2)), latch); 889 } 890 891 static void 892 p9100_clearscreen(struct p9100_softc *sc) 893 { 894 895 p9100_rectfill(sc, 0, 0, sc->sc_width, sc->sc_height, sc->sc_bg); 896 } 897 #endif /* NWSDISPLAY > 0 */ 898 899 static uint8_t 900 p9100_ramdac_read(struct p9100_softc *sc, bus_size_t off) 901 { 902 903 (void)p9100_ctl_read_4(sc, PWRUP_CNFG); 904 return ((bus_space_read_4(sc->sc_bustag, 905 sc->sc_ctl_memh, off) >> 16) & 0xff); 906 } 907 908 static void 909 p9100_ramdac_write(struct p9100_softc *sc, bus_size_t off, uint8_t v) 910 { 911 912 (void)p9100_ctl_read_4(sc, PWRUP_CNFG); 913 bus_space_write_4(sc->sc_bustag, sc->sc_ctl_memh, off, 914 ((uint32_t)v) << 16); 915 } 916 917 static uint8_t 918 p9100_ramdac_read_ctl(struct p9100_softc *sc, int off) 919 { 920 p9100_ramdac_write(sc, DAC_INDX_LO, off & 0xff); 921 p9100_ramdac_write(sc, DAC_INDX_HI, (off & 0xff00) >> 8); 922 return p9100_ramdac_read(sc, DAC_INDX_DATA); 923 } 924 925 static void 926 p9100_ramdac_write_ctl(struct p9100_softc *sc, int off, uint8_t val) 927 { 928 p9100_ramdac_write(sc, DAC_INDX_LO, off & 0xff); 929 p9100_ramdac_write(sc, DAC_INDX_HI, (off & 0xff00) >> 8); 930 p9100_ramdac_write(sc, DAC_INDX_DATA, val); 931 } 932 933 /* 934 * Undo the effect of an FBIOSVIDEO that turns the video off. 935 */ 936 static void 937 p9100unblank(device_t dev) 938 { 939 struct p9100_softc *sc = device_private(dev); 940 941 p9100_set_video(sc, 1); 942 943 /* 944 * Check if we're in terminal mode. If not force the console screen 945 * to front so we can see ddb, panic messages and so on 946 */ 947 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) { 948 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 949 if (sc->vd.active != &p9100_console_screen) { 950 SCREEN_INVISIBLE(sc->vd.active); 951 sc->vd.active = &p9100_console_screen; 952 SCREEN_VISIBLE(&p9100_console_screen); 953 } 954 p9100_init_engine(sc); 955 p9100_set_depth(sc, 8); 956 vcons_redraw_screen(&p9100_console_screen); 957 } 958 } 959 960 static void 961 p9100_set_video(struct p9100_softc *sc, int enable) 962 { 963 uint32_t v = p9100_ctl_read_4(sc, SCRN_RPNT_CTL_1); 964 965 if (enable) 966 v |= VIDEO_ENABLED; 967 else 968 v &= ~VIDEO_ENABLED; 969 p9100_ctl_write_4(sc, SCRN_RPNT_CTL_1, v); 970 #if NTCTRL > 0 971 /* Turn On/Off the TFT if we know how. 972 */ 973 tadpole_set_video(enable); 974 #endif 975 } 976 977 static int 978 p9100_get_video(struct p9100_softc *sc) 979 { 980 return (p9100_ctl_read_4(sc, SCRN_RPNT_CTL_1) & VIDEO_ENABLED) != 0; 981 } 982 983 static bool 984 p9100_suspend(device_t dev, const pmf_qual_t *qual) 985 { 986 struct p9100_softc *sc = device_private(dev); 987 988 if (sc->sc_powerstate == PWR_SUSPEND) 989 return TRUE; 990 991 sc->sc_video = p9100_get_video(sc); 992 sc->sc_dac_power = p9100_ramdac_read_ctl(sc, DAC_POWER_MGT); 993 p9100_ramdac_write_ctl(sc, DAC_POWER_MGT, 994 DAC_POWER_SCLK_DISABLE | 995 DAC_POWER_DDOT_DISABLE | 996 DAC_POWER_SYNC_DISABLE | 997 DAC_POWER_ICLK_DISABLE | 998 DAC_POWER_IPWR_DISABLE); 999 p9100_set_video(sc, 0); 1000 sc->sc_powerstate = PWR_SUSPEND; 1001 return TRUE; 1002 } 1003 1004 static bool 1005 p9100_resume(device_t dev, const pmf_qual_t *qual) 1006 { 1007 struct p9100_softc *sc = device_private(dev); 1008 1009 if (sc->sc_powerstate == PWR_RESUME) 1010 return TRUE; 1011 1012 p9100_ramdac_write_ctl(sc, DAC_POWER_MGT, sc->sc_dac_power); 1013 p9100_set_video(sc, sc->sc_video); 1014 1015 sc->sc_powerstate = PWR_RESUME; 1016 return TRUE; 1017 } 1018 1019 /* 1020 * Load a subset of the current (new) colormap into the IBM RAMDAC. 1021 */ 1022 static void 1023 p9100loadcmap(struct p9100_softc *sc, int start, int ncolors) 1024 { 1025 int i; 1026 sc->sc_last_offset = 0xffffffff; 1027 1028 p9100_ramdac_write(sc, DAC_CMAP_WRIDX, start); 1029 1030 for (i=0;i<ncolors;i++) { 1031 p9100_ramdac_write(sc, DAC_CMAP_DATA, 1032 sc->sc_cmap.cm_map[i + start][0]); 1033 p9100_ramdac_write(sc, DAC_CMAP_DATA, 1034 sc->sc_cmap.cm_map[i + start][1]); 1035 p9100_ramdac_write(sc, DAC_CMAP_DATA, 1036 sc->sc_cmap.cm_map[i + start][2]); 1037 } 1038 } 1039 1040 /* 1041 * Return the address that would map the given device at the given 1042 * offset, allowing for the given protection, or return -1 for error. 1043 */ 1044 static paddr_t 1045 p9100mmap(dev_t dev, off_t off, int prot) 1046 { 1047 struct p9100_softc *sc = device_lookup_private(&pnozz_cd, minor(dev)); 1048 1049 if (off & PGOFSET) 1050 panic("p9100mmap"); 1051 if (off < 0) 1052 return (-1); 1053 1054 #ifdef PNOZZ_EMUL_CG3 1055 #define CG3_MMAP_OFFSET 0x04000000 1056 /* Make Xsun think we are a CG3 (SUN3COLOR) 1057 */ 1058 if (off >= CG3_MMAP_OFFSET && off < CG3_MMAP_OFFSET + sc->sc_fb_psize) { 1059 off -= CG3_MMAP_OFFSET; 1060 return (bus_space_mmap(sc->sc_bustag, 1061 sc->sc_fb_paddr, 1062 off, 1063 prot, 1064 BUS_SPACE_MAP_LINEAR)); 1065 } 1066 #endif 1067 1068 if (off >= sc->sc_fb_psize + sc->sc_ctl_psize/* + sc->sc_cmd_psize*/) 1069 return (-1); 1070 1071 if (off < sc->sc_fb_psize) { 1072 return (bus_space_mmap(sc->sc_bustag, 1073 sc->sc_fb_paddr, 1074 off, 1075 prot, 1076 BUS_SPACE_MAP_LINEAR)); 1077 } 1078 1079 off -= sc->sc_fb_psize; 1080 if (off < sc->sc_ctl_psize) { 1081 return (bus_space_mmap(sc->sc_bustag, 1082 sc->sc_ctl_paddr, 1083 off, 1084 prot, 1085 BUS_SPACE_MAP_LINEAR)); 1086 } 1087 1088 return EINVAL; 1089 } 1090 1091 /* wscons stuff */ 1092 #if NWSDISPLAY > 0 1093 1094 static void 1095 p9100_cursor(void *cookie, int on, int row, int col) 1096 { 1097 struct rasops_info *ri = cookie; 1098 struct vcons_screen *scr = ri->ri_hw; 1099 struct p9100_softc *sc = scr->scr_cookie; 1100 int x, y, wi,he; 1101 1102 wi = ri->ri_font->fontwidth; 1103 he = ri->ri_font->fontheight; 1104 1105 if (ri->ri_flg & RI_CURSOR) { 1106 x = ri->ri_ccol * wi + ri->ri_xorigin; 1107 y = ri->ri_crow * he + ri->ri_yorigin; 1108 p9100_bitblt(sc, x, y, x, y, wi, he, ROP_SRC ^ 0xff); 1109 ri->ri_flg &= ~RI_CURSOR; 1110 } 1111 1112 ri->ri_crow = row; 1113 ri->ri_ccol = col; 1114 1115 if (on) 1116 { 1117 x = ri->ri_ccol * wi + ri->ri_xorigin; 1118 y = ri->ri_crow * he + ri->ri_yorigin; 1119 p9100_bitblt(sc, x, y, x, y, wi, he, ROP_SRC ^ 0xff); 1120 ri->ri_flg |= RI_CURSOR; 1121 } 1122 } 1123 1124 #if 0 1125 static int 1126 p9100_mapchar(void *cookie, int uni, u_int *index) 1127 { 1128 return 0; 1129 } 1130 #endif 1131 1132 static void 1133 p9100_putchar(void *cookie, int row, int col, u_int c, long attr) 1134 { 1135 struct rasops_info *ri = cookie; 1136 struct wsdisplay_font *font = PICK_FONT(ri, c); 1137 struct vcons_screen *scr = ri->ri_hw; 1138 struct p9100_softc *sc = scr->scr_cookie; 1139 1140 int fg, bg, i; 1141 uint8_t *data; 1142 int x, y, wi, he; 1143 1144 wi = font->fontwidth; 1145 he = font->fontheight; 1146 1147 if (!CHAR_IN_FONT(c, font)) 1148 return; 1149 1150 bg = (u_char)ri->ri_devcmap[(attr >> 16) & 0xff]; 1151 fg = (u_char)ri->ri_devcmap[(attr >> 24) & 0xff]; 1152 x = ri->ri_xorigin + col * wi; 1153 y = ri->ri_yorigin + row * he; 1154 1155 if (c == 0x20) { 1156 p9100_rectfill(sc, x, y, wi, he, bg); 1157 } else { 1158 data = WSFONT_GLYPH(c, font); 1159 1160 p9100_setup_mono(sc, x, y, wi, 1, fg, bg); 1161 for (i = 0; i < he; i++) { 1162 p9100_feed_line(sc, font->stride, 1163 data); 1164 data += font->stride; 1165 } 1166 } 1167 } 1168 1169 static void 1170 p9100_putchar_aa(void *cookie, int row, int col, u_int c, long attr) 1171 { 1172 struct rasops_info *ri = cookie; 1173 struct wsdisplay_font *font = PICK_FONT(ri, c); 1174 struct vcons_screen *scr = ri->ri_hw; 1175 struct p9100_softc *sc = scr->scr_cookie; 1176 uint32_t bg, latch = 0, bg8, fg8, pixel; 1177 int i, j, x, y, wi, he, r, g, b, aval, rwi; 1178 int r1, g1, b1, r0, g0, b0, fgo, bgo; 1179 uint8_t *data8; 1180 int rv; 1181 1182 if (sc->sc_mode != WSDISPLAYIO_MODE_EMUL) 1183 return; 1184 1185 if (!CHAR_IN_FONT(c, font)) 1186 return; 1187 1188 wi = font->fontwidth; 1189 rwi = (wi + 3) & ~3; 1190 he = font->fontheight; 1191 1192 bg = ri->ri_devcmap[(attr >> 16) & 0xf]; 1193 x = ri->ri_xorigin + col * wi; 1194 y = ri->ri_yorigin + row * he; 1195 1196 if (c == 0x20) { 1197 p9100_rectfill(sc, x, y, wi, he, bg); 1198 return; 1199 } 1200 1201 rv = glyphcache_try(&sc->sc_gc, c, x, y, attr); 1202 if (rv == GC_OK) 1203 return; 1204 1205 data8 = WSFONT_GLYPH(c, font); 1206 1207 p9100_sync(sc); 1208 1209 p9100_ctl_write_4(sc, RASTER_OP, ROP_SRC); 1210 p9100_ctl_write_4(sc, ABS_X0, x); 1211 p9100_ctl_write_4(sc, ABS_XY1, (x << 16) | (y & 0xFFFFL)); 1212 p9100_ctl_write_4(sc, ABS_X2, (x + rwi)); 1213 p9100_ctl_write_4(sc, ABS_Y3, 1); 1214 p9100_ctl_write_4(sc, BYTE_CLIP_MAX, ((x + wi - 1) << 16) | 0x3fff); 1215 1216 /* 1217 * we need the RGB colours here, so get offsets into rasops_cmap 1218 */ 1219 fgo = ((attr >> 24) & 0xf) * 3; 1220 bgo = ((attr >> 16) & 0xf) * 3; 1221 1222 r0 = rasops_cmap[bgo]; 1223 r1 = rasops_cmap[fgo]; 1224 g0 = rasops_cmap[bgo + 1]; 1225 g1 = rasops_cmap[fgo + 1]; 1226 b0 = rasops_cmap[bgo + 2]; 1227 b1 = rasops_cmap[fgo + 2]; 1228 #define R3G3B2(r, g, b) ((r & 0xe0) | ((g >> 3) & 0x1c) | (b >> 6)) 1229 bg8 = R3G3B2(r0, g0, b0); 1230 fg8 = R3G3B2(r1, g1, b1); 1231 1232 //r128fb_wait(sc, 16); 1233 1234 for (i = 0; i < he; i++) { 1235 for (j = 0; j < wi; j++) { 1236 aval = *data8; 1237 if (aval == 0) { 1238 pixel = bg8; 1239 } else if (aval == 255) { 1240 pixel = fg8; 1241 } else { 1242 r = aval * r1 + (255 - aval) * r0; 1243 g = aval * g1 + (255 - aval) * g0; 1244 b = aval * b1 + (255 - aval) * b0; 1245 pixel = ((r & 0xe000) >> 8) | 1246 ((g & 0xe000) >> 11) | 1247 ((b & 0xc000) >> 14); 1248 } 1249 latch = (latch << 8) | pixel; 1250 /* write in 32bit chunks */ 1251 if ((j & 3) == 3) { 1252 bus_space_write_4(sc->sc_bustag, sc->sc_ctl_memh, 1253 COMMAND_PIXEL8, latch); 1254 latch = 0; 1255 } 1256 data8++; 1257 } 1258 /* if we have pixels left in latch write them out */ 1259 if ((j & 3) != 0) { 1260 latch = latch << ((4 - (j & 3)) << 3); 1261 bus_space_write_4(sc->sc_bustag, sc->sc_ctl_memh, 1262 COMMAND_PIXEL8, latch); 1263 } 1264 } 1265 if (rv == GC_ADD) { 1266 glyphcache_add(&sc->sc_gc, c, x, y); 1267 } 1268 } 1269 1270 /* 1271 * wsdisplay_accessops 1272 */ 1273 1274 int 1275 p9100_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 1276 struct lwp *l) 1277 { 1278 struct vcons_data *vd = v; 1279 struct p9100_softc *sc = vd->cookie; 1280 struct wsdisplay_fbinfo *wdf; 1281 struct vcons_screen *ms = vd->active; 1282 1283 switch (cmd) { 1284 case WSDISPLAYIO_GTYPE: 1285 *(u_int *)data = WSDISPLAY_TYPE_SB_P9100; 1286 return 0; 1287 1288 case FBIOGVIDEO: 1289 case WSDISPLAYIO_GVIDEO: 1290 *(int *)data = p9100_get_video(sc); 1291 return 0; 1292 1293 case WSDISPLAYIO_SVIDEO: 1294 case FBIOSVIDEO: 1295 p9100_set_video(sc, *(int *)data); 1296 return 0; 1297 1298 case WSDISPLAYIO_GINFO: 1299 wdf = (void *)data; 1300 wdf->height = ms->scr_ri.ri_height; 1301 wdf->width = ms->scr_ri.ri_width; 1302 wdf->depth = ms->scr_ri.ri_depth; 1303 wdf->cmsize = 256; 1304 return 0; 1305 1306 case WSDISPLAYIO_GETCMAP: 1307 return p9100_getcmap(sc, (struct wsdisplay_cmap *)data); 1308 1309 case WSDISPLAYIO_PUTCMAP: 1310 return p9100_putcmap(sc, (struct wsdisplay_cmap *)data); 1311 1312 case WSDISPLAYIO_SMODE: 1313 { 1314 int new_mode = *(int*)data; 1315 if (new_mode != sc->sc_mode) 1316 { 1317 sc->sc_mode = new_mode; 1318 if (new_mode == WSDISPLAYIO_MODE_EMUL) 1319 { 1320 p9100_init_engine(sc); 1321 p9100_set_depth(sc, 8); 1322 p9100loadcmap(sc, 0, 256); 1323 p9100_clearscreen(sc); 1324 glyphcache_wipe(&sc->sc_gc); 1325 vcons_redraw_screen(ms); 1326 } 1327 } 1328 } 1329 } 1330 return EPASSTHROUGH; 1331 } 1332 1333 static paddr_t 1334 p9100_mmap(void *v, void *vs, off_t offset, int prot) 1335 { 1336 struct vcons_data *vd = v; 1337 struct p9100_softc *sc = vd->cookie; 1338 paddr_t pa; 1339 1340 /* 'regular' framebuffer mmap()ing */ 1341 if (offset < sc->sc_fb_psize) { 1342 pa = bus_space_mmap(sc->sc_bustag, sc->sc_fb_paddr + offset, 0, 1343 prot, BUS_SPACE_MAP_LINEAR); 1344 return pa; 1345 } 1346 1347 if ((offset >= sc->sc_fb_paddr) && (offset < (sc->sc_fb_paddr + 1348 sc->sc_fb_psize))) { 1349 pa = bus_space_mmap(sc->sc_bustag, offset, 0, prot, 1350 BUS_SPACE_MAP_LINEAR); 1351 return pa; 1352 } 1353 1354 if ((offset >= sc->sc_ctl_paddr) && (offset < (sc->sc_ctl_paddr + 1355 sc->sc_ctl_psize))) { 1356 pa = bus_space_mmap(sc->sc_bustag, offset, 0, prot, 1357 BUS_SPACE_MAP_LINEAR); 1358 return pa; 1359 } 1360 1361 return -1; 1362 } 1363 1364 static void 1365 p9100_init_screen(void *cookie, struct vcons_screen *scr, 1366 int existing, long *defattr) 1367 { 1368 struct p9100_softc *sc = cookie; 1369 struct rasops_info *ri = &scr->scr_ri; 1370 1371 ri->ri_depth = sc->sc_depth << 3; 1372 ri->ri_width = sc->sc_width; 1373 ri->ri_height = sc->sc_height; 1374 ri->ri_stride = sc->sc_stride; 1375 ri->ri_flg = RI_CENTER | RI_FULLCLEAR; 1376 if (ri->ri_depth == 8) 1377 ri->ri_flg |= RI_8BIT_IS_RGB | RI_ENABLE_ALPHA; 1378 1379 #ifdef PNOZZ_USE_LATCH 1380 ri->ri_bits = bus_space_vaddr(sc->sc_bustag, sc->sc_fb_memh); 1381 DPRINTF("addr: %08lx\n",(ulong)ri->ri_bits); 1382 #endif 1383 1384 rasops_init(ri, 0, 0); 1385 ri->ri_caps = WSSCREEN_WSCOLORS; 1386 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 1387 sc->sc_width / ri->ri_font->fontwidth); 1388 1389 /* enable acceleration */ 1390 ri->ri_ops.cursor = p9100_cursor; 1391 ri->ri_ops.copyrows = p9100_copyrows; 1392 ri->ri_ops.eraserows = p9100_eraserows; 1393 ri->ri_ops.copycols = p9100_copycols; 1394 ri->ri_ops.erasecols = p9100_erasecols; 1395 if (FONT_IS_ALPHA(ri->ri_font)) { 1396 ri->ri_ops.putchar = p9100_putchar_aa; 1397 } else 1398 ri->ri_ops.putchar = p9100_putchar; 1399 } 1400 1401 static int 1402 p9100_putcmap(struct p9100_softc *sc, struct wsdisplay_cmap *cm) 1403 { 1404 u_int index = cm->index; 1405 u_int count = cm->count; 1406 int i, error; 1407 u_char rbuf[256], gbuf[256], bbuf[256]; 1408 u_char *r, *g, *b; 1409 1410 if (cm->index >= 256 || cm->count > 256 || 1411 (cm->index + cm->count) > 256) 1412 return EINVAL; 1413 error = copyin(cm->red, &rbuf[index], count); 1414 if (error) 1415 return error; 1416 error = copyin(cm->green, &gbuf[index], count); 1417 if (error) 1418 return error; 1419 error = copyin(cm->blue, &bbuf[index], count); 1420 if (error) 1421 return error; 1422 1423 r = &rbuf[index]; 1424 g = &gbuf[index]; 1425 b = &bbuf[index]; 1426 1427 for (i = 0; i < count; i++) { 1428 sc->sc_cmap.cm_map[index][0] = *r; 1429 sc->sc_cmap.cm_map[index][1] = *g; 1430 sc->sc_cmap.cm_map[index][2] = *b; 1431 index++; 1432 r++, g++, b++; 1433 } 1434 p9100loadcmap(sc, 0, 256); 1435 return 0; 1436 } 1437 1438 static int 1439 p9100_getcmap(struct p9100_softc *sc, struct wsdisplay_cmap *cm) 1440 { 1441 u_int index = cm->index; 1442 u_int count = cm->count; 1443 int error, i; 1444 uint8_t red[256], green[256], blue[256]; 1445 1446 if (index >= 255 || count > 256 || index + count > 256) 1447 return EINVAL; 1448 1449 i = index; 1450 while (i < (index + count)) { 1451 red[i] = sc->sc_cmap.cm_map[i][0]; 1452 green[i] = sc->sc_cmap.cm_map[i][1]; 1453 blue[i] = sc->sc_cmap.cm_map[i][2]; 1454 i++; 1455 } 1456 error = copyout(&red[index], cm->red, count); 1457 if (error) 1458 return error; 1459 error = copyout(&green[index], cm->green, count); 1460 if (error) 1461 return error; 1462 error = copyout(&blue[index], cm->blue, count); 1463 if (error) 1464 return error; 1465 1466 return 0; 1467 } 1468 1469 static void 1470 p9100_copycols(void *cookie, int row, int srccol, int dstcol, int ncols) 1471 { 1472 struct rasops_info *ri = cookie; 1473 struct vcons_screen *scr = ri->ri_hw; 1474 int32_t xs, xd, y, width, height; 1475 1476 xs = ri->ri_xorigin + ri->ri_font->fontwidth * srccol; 1477 xd = ri->ri_xorigin + ri->ri_font->fontwidth * dstcol; 1478 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1479 width = ri->ri_font->fontwidth * ncols; 1480 height = ri->ri_font->fontheight; 1481 p9100_bitblt(scr->scr_cookie, xs, y, xd, y, width, height, ROP_SRC); 1482 } 1483 1484 static void 1485 p9100_erasecols(void *cookie, int row, int startcol, int ncols, long fillattr) 1486 { 1487 struct rasops_info *ri = cookie; 1488 struct vcons_screen *scr = ri->ri_hw; 1489 int32_t x, y, width, height, bg; 1490 1491 x = ri->ri_xorigin + ri->ri_font->fontwidth * startcol; 1492 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1493 width = ri->ri_font->fontwidth * ncols; 1494 height = ri->ri_font->fontheight; 1495 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff]; 1496 p9100_rectfill(scr->scr_cookie, x, y, width, height, bg); 1497 } 1498 1499 static void 1500 p9100_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 1501 { 1502 struct rasops_info *ri = cookie; 1503 struct vcons_screen *scr = ri->ri_hw; 1504 int32_t x, ys, yd, width, height; 1505 1506 x = ri->ri_xorigin; 1507 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 1508 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 1509 width = ri->ri_emuwidth; 1510 height = ri->ri_font->fontheight * nrows; 1511 p9100_bitblt(scr->scr_cookie, x, ys, x, yd, width, height, ROP_SRC); 1512 } 1513 1514 static void 1515 p9100_eraserows(void *cookie, int row, int nrows, long fillattr) 1516 { 1517 struct rasops_info *ri = cookie; 1518 struct vcons_screen *scr = ri->ri_hw; 1519 int32_t x, y, width, height, bg; 1520 1521 if ((row == 0) && (nrows == ri->ri_rows)) { 1522 x = y = 0; 1523 width = ri->ri_width; 1524 height = ri->ri_height; 1525 } else { 1526 x = ri->ri_xorigin; 1527 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 1528 width = ri->ri_emuwidth; 1529 height = ri->ri_font->fontheight * nrows; 1530 } 1531 bg = (uint32_t)ri->ri_devcmap[(fillattr >> 16) & 0xff]; 1532 p9100_rectfill(scr->scr_cookie, x, y, width, height, bg); 1533 } 1534 1535 #if 0 1536 static int 1537 p9100_load_font(void *v, void *cookie, struct wsdisplay_font *data) 1538 { 1539 1540 return 0; 1541 } 1542 #endif 1543 1544 #endif /* NWSDISPLAY > 0 */ 1545 1546 #if 0 1547 static int 1548 p9100_intr(void *arg) 1549 { 1550 /*p9100_softc *sc=arg;*/ 1551 DPRINTF("."); 1552 return 1; 1553 } 1554 #endif 1555 1556 static void 1557 p9100_init_cursor(struct p9100_softc *sc) 1558 { 1559 1560 memset(&sc->sc_cursor, 0, sizeof(struct pnozz_cursor)); 1561 sc->sc_cursor.pc_size.x = 64; 1562 sc->sc_cursor.pc_size.y = 64; 1563 1564 } 1565 1566 static void 1567 p9100_set_fbcursor(struct p9100_softc *sc) 1568 { 1569 #ifdef PNOZZ_PARANOID 1570 int s; 1571 1572 s = splhigh(); /* just in case... */ 1573 #endif 1574 sc->sc_last_offset = 0xffffffff; 1575 1576 /* set position and hotspot */ 1577 p9100_ramdac_write(sc, DAC_INDX_CTL, DAC_INDX_AUTOINCR); 1578 p9100_ramdac_write(sc, DAC_INDX_HI, 0); 1579 p9100_ramdac_write(sc, DAC_INDX_LO, DAC_CURSOR_CTL); 1580 if (sc->sc_cursor.pc_enable) { 1581 p9100_ramdac_write(sc, DAC_INDX_DATA, DAC_CURSOR_X11 | 1582 DAC_CURSOR_64); 1583 } else 1584 p9100_ramdac_write(sc, DAC_INDX_DATA, DAC_CURSOR_OFF); 1585 /* next two registers - x low, high, y low, high */ 1586 p9100_ramdac_write(sc, DAC_INDX_DATA, sc->sc_cursor.pc_pos.x & 0xff); 1587 p9100_ramdac_write(sc, DAC_INDX_DATA, (sc->sc_cursor.pc_pos.x >> 8) & 1588 0xff); 1589 p9100_ramdac_write(sc, DAC_INDX_DATA, sc->sc_cursor.pc_pos.y & 0xff); 1590 p9100_ramdac_write(sc, DAC_INDX_DATA, (sc->sc_cursor.pc_pos.y >> 8) & 1591 0xff); 1592 /* hotspot */ 1593 p9100_ramdac_write(sc, DAC_INDX_DATA, sc->sc_cursor.pc_hot.x & 0xff); 1594 p9100_ramdac_write(sc, DAC_INDX_DATA, sc->sc_cursor.pc_hot.y & 0xff); 1595 1596 #ifdef PNOZZ_PARANOID 1597 splx(s); 1598 #endif 1599 1600 } 1601 1602 static void 1603 p9100_setcursorcmap(struct p9100_softc *sc) 1604 { 1605 int i; 1606 1607 #ifdef PNOZZ_PARANOID 1608 int s; 1609 s = splhigh(); /* just in case... */ 1610 #endif 1611 sc->sc_last_offset = 0xffffffff; 1612 1613 /* set cursor colours */ 1614 p9100_ramdac_write(sc, DAC_INDX_CTL, DAC_INDX_AUTOINCR); 1615 p9100_ramdac_write(sc, DAC_INDX_HI, 0); 1616 p9100_ramdac_write(sc, DAC_INDX_LO, DAC_CURSOR_COL_1); 1617 1618 for (i = 0; i < 3; i++) { 1619 p9100_ramdac_write(sc, DAC_INDX_DATA, sc->sc_cursor.red[i]); 1620 p9100_ramdac_write(sc, DAC_INDX_DATA, sc->sc_cursor.green[i]); 1621 p9100_ramdac_write(sc, DAC_INDX_DATA, sc->sc_cursor.blue[i]); 1622 } 1623 1624 #ifdef PNOZZ_PARANOID 1625 splx(s); 1626 #endif 1627 } 1628 1629 static void 1630 p9100_loadcursor(struct p9100_softc *sc) 1631 { 1632 uint32_t *image, *mask; 1633 uint32_t bit, bbit, im, ma; 1634 int i, j, k; 1635 uint8_t latch1, latch2; 1636 1637 #ifdef PNOZZ_PARANOID 1638 int s; 1639 s = splhigh(); /* just in case... */ 1640 #endif 1641 sc->sc_last_offset = 0xffffffff; 1642 1643 /* set cursor shape */ 1644 p9100_ramdac_write(sc, DAC_INDX_CTL, DAC_INDX_AUTOINCR); 1645 p9100_ramdac_write(sc, DAC_INDX_HI, 1); 1646 p9100_ramdac_write(sc, DAC_INDX_LO, 0); 1647 1648 image = sc->sc_cursor.pc_bits; 1649 mask = &sc->sc_cursor.pc_bits[0x80]; 1650 1651 for (i = 0; i < 0x80; i++) { 1652 bit = 0x80000000; 1653 im = image[i]; 1654 ma = mask[i]; 1655 for (k = 0; k < 4; k++) { 1656 bbit = 0x1; 1657 latch1 = 0; 1658 for (j = 0; j < 4; j++) { 1659 if (im & bit) 1660 latch1 |= bbit; 1661 bbit <<= 1; 1662 if (ma & bit) 1663 latch1 |= bbit; 1664 bbit <<= 1; 1665 bit >>= 1; 1666 } 1667 bbit = 0x1; 1668 latch2 = 0; 1669 for (j = 0; j < 4; j++) { 1670 if (im & bit) 1671 latch2 |= bbit; 1672 bbit <<= 1; 1673 if (ma & bit) 1674 latch2 |= bbit; 1675 bbit <<= 1; 1676 bit >>= 1; 1677 } 1678 p9100_ramdac_write(sc, DAC_INDX_DATA, latch1); 1679 p9100_ramdac_write(sc, DAC_INDX_DATA, latch2); 1680 } 1681 } 1682 #ifdef PNOZZ_DEBUG_CURSOR 1683 printf("image:\n"); 1684 for (i=0;i<0x80;i+=2) 1685 printf("%08x %08x\n", image[i], image[i+1]); 1686 printf("mask:\n"); 1687 for (i=0;i<0x80;i+=2) 1688 printf("%08x %08x\n", mask[i], mask[i+1]); 1689 #endif 1690 #ifdef PNOZZ_PARANOID 1691 splx(s); 1692 #endif 1693 } 1694 1695 #if NTCTRL > 0 1696 static void 1697 p9100_set_extvga(void *cookie, int status) 1698 { 1699 struct p9100_softc *sc = cookie; 1700 #ifdef PNOZZ_PARANOID 1701 int s; 1702 1703 s = splhigh(); 1704 #endif 1705 1706 #ifdef PNOZZ_DEBUG 1707 printf("%s: external VGA %s\n", device_xname(sc->sc_dev), 1708 status ? "on" : "off"); 1709 #endif 1710 1711 sc->sc_last_offset = 0xffffffff; 1712 1713 if (status) { 1714 p9100_ramdac_write_ctl(sc, DAC_POWER_MGT, 1715 p9100_ramdac_read_ctl(sc, DAC_POWER_MGT) & 1716 ~DAC_POWER_IPWR_DISABLE); 1717 } else { 1718 p9100_ramdac_write_ctl(sc, DAC_POWER_MGT, 1719 p9100_ramdac_read_ctl(sc, DAC_POWER_MGT) | 1720 DAC_POWER_IPWR_DISABLE); 1721 } 1722 #ifdef PNOZZ_PARANOID 1723 splx(s); 1724 #endif 1725 } 1726 #endif /* NTCTRL > 0 */ 1727 1728 static int 1729 upper_bit(uint32_t b) 1730 { 1731 uint32_t mask=0x80000000; 1732 int cnt = 31; 1733 if (b == 0) 1734 return -1; 1735 while ((mask != 0) && ((b & mask) == 0)) { 1736 mask = mask >> 1; 1737 cnt--; 1738 } 1739 return cnt; 1740 } 1741 1742 static int 1743 p9100_set_depth(struct p9100_softc *sc, int depth) 1744 { 1745 int new_sls; 1746 uint32_t bits, scr, memctl, mem; 1747 int s0, s1, s2, s3, ps, crtcline; 1748 uint8_t pf, mc3, es; 1749 1750 switch (depth) { 1751 case 8: 1752 sc->sc_depthshift = 0; 1753 ps = 2; 1754 pf = 3; 1755 mc3 = 0; 1756 es = 0; /* no swapping */ 1757 memctl = 3; 1758 break; 1759 case 16: 1760 sc->sc_depthshift = 1; 1761 ps = 3; 1762 pf = 4; 1763 mc3 = 0; 1764 es = 2; /* swap bytes in 16bit words */ 1765 memctl = 2; 1766 break; 1767 case 24: 1768 /* boo */ 1769 printf("We don't DO 24bit pixels dammit!\n"); 1770 return 0; 1771 case 32: 1772 sc->sc_depthshift = 2; 1773 ps = 5; 1774 pf = 6; 1775 mc3 = 0; 1776 es = 6; /* swap both half-words and bytes */ 1777 memctl = 1; /* 0 */ 1778 break; 1779 default: 1780 aprint_error("%s: bogus colour depth (%d)\n", 1781 __func__, depth); 1782 return FALSE; 1783 } 1784 /* 1785 * this could be done a lot shorter and faster but then nobody would 1786 * understand what the hell we're doing here without getting a major 1787 * headache. Scanline size is encoded as 4 shift values, 3 of them 3 bits 1788 * wide, 16 << n for n>0, one 2 bits, 512 << n for n>0. n==0 means 0 1789 */ 1790 new_sls = sc->sc_width << sc->sc_depthshift; 1791 sc->sc_stride = new_sls; 1792 bits = new_sls; 1793 s3 = upper_bit(bits); 1794 if (s3 > 9) { 1795 bits &= ~(1 << s3); 1796 s3 -= 9; 1797 } else 1798 s3 = 0; 1799 s2 = upper_bit(bits); 1800 if (s2 > 0) { 1801 bits &= ~(1 << s2); 1802 s2 -= 4; 1803 } else 1804 s2 = 0; 1805 s1 = upper_bit(bits); 1806 if (s1 > 0) { 1807 bits &= ~(1 << s1); 1808 s1 -= 4; 1809 } else 1810 s1 = 0; 1811 s0 = upper_bit(bits); 1812 if (s0 > 0) { 1813 bits &= ~(1 << s0); 1814 s0 -= 4; 1815 } else 1816 s0 = 0; 1817 1818 1819 DPRINTF("sls: %x sh: %d %d %d %d leftover: %x\n", new_sls, s0, s1, 1820 s2, s3, bits); 1821 1822 /* 1823 * now let's put these values into the System Config Register. No need to 1824 * read it here since we (hopefully) just saved the content 1825 */ 1826 scr = p9100_ctl_read_4(sc, SYS_CONF); 1827 scr = (s0 << SHIFT_0) | (s1 << SHIFT_1) | (s2 << SHIFT_2) | 1828 (s3 << SHIFT_3) | (ps << PIXEL_SHIFT) | (es << SWAP_SHIFT); 1829 1830 DPRINTF("new scr: %x DAC %x %x\n", scr, pf, mc3); 1831 1832 mem = p9100_ctl_read_4(sc, VID_MEM_CONFIG); 1833 1834 DPRINTF("old memctl: %08x\n", mem); 1835 1836 /* set shift and crtc clock */ 1837 mem &= ~(0x0000fc00); 1838 mem |= (memctl << 10) | (memctl << 13); 1839 p9100_ctl_write_4(sc, VID_MEM_CONFIG, mem); 1840 1841 DPRINTF("new memctl: %08x\n", mem); 1842 1843 /* whack the engine... */ 1844 p9100_ctl_write_4(sc, SYS_CONF, scr); 1845 1846 /* ok, whack the DAC */ 1847 p9100_ramdac_write_ctl(sc, DAC_MISC_1, 0x11); 1848 p9100_ramdac_write_ctl(sc, DAC_MISC_2, 0x45); 1849 p9100_ramdac_write_ctl(sc, DAC_MISC_3, mc3); 1850 /* 1851 * despite the 3GX manual saying otherwise we don't need to mess with 1852 * any clock dividers here 1853 */ 1854 p9100_ramdac_write_ctl(sc, DAC_MISC_CLK, 1); 1855 p9100_ramdac_write_ctl(sc, 3, 0); 1856 p9100_ramdac_write_ctl(sc, 4, 0); 1857 1858 p9100_ramdac_write_ctl(sc, DAC_POWER_MGT, 0); 1859 p9100_ramdac_write_ctl(sc, DAC_OPERATION, 0); 1860 p9100_ramdac_write_ctl(sc, DAC_PALETTE_CTRL, 0); 1861 1862 p9100_ramdac_write_ctl(sc, DAC_PIXEL_FMT, pf); 1863 1864 /* TODO: distinguish between 15 and 16 bit */ 1865 p9100_ramdac_write_ctl(sc, DAC_8BIT_CTRL, 0); 1866 /* direct colour, linear, 565 */ 1867 p9100_ramdac_write_ctl(sc, DAC_16BIT_CTRL, 0xc6); 1868 /* direct colour */ 1869 p9100_ramdac_write_ctl(sc, DAC_32BIT_CTRL, 3); 1870 1871 /* From the 3GX manual. Needs magic number reduction */ 1872 p9100_ramdac_write_ctl(sc, 0x10, 2); 1873 p9100_ramdac_write_ctl(sc, 0x11, 0); 1874 p9100_ramdac_write_ctl(sc, 0x14, 5); 1875 p9100_ramdac_write_ctl(sc, 0x08, 1); 1876 p9100_ramdac_write_ctl(sc, 0x15, 5); 1877 p9100_ramdac_write_ctl(sc, 0x16, 0x63); 1878 1879 /* whack the CRTC */ 1880 /* we always transfer 64bit in one go */ 1881 crtcline = sc->sc_stride >> 3; 1882 1883 DPRINTF("crtcline: %d\n", crtcline); 1884 1885 p9100_ctl_write_4(sc, VID_HTOTAL, (24 << sc->sc_depthshift) + crtcline); 1886 p9100_ctl_write_4(sc, VID_HSRE, 8 << sc->sc_depthshift); 1887 p9100_ctl_write_4(sc, VID_HBRE, 18 << sc->sc_depthshift); 1888 p9100_ctl_write_4(sc, VID_HBFE, (18 << sc->sc_depthshift) + crtcline); 1889 1890 #ifdef PNOZZ_DEBUG 1891 { 1892 uint32_t sscr; 1893 sscr = p9100_ctl_read_4(sc, SYS_CONF); 1894 printf("scr: %x\n", sscr); 1895 } 1896 #endif 1897 return TRUE; 1898 } 1899