xcfb.c revision 1.13
1/* $NetBSD: xcfb.c,v 1.13 1999/11/29 07:50:55 nisimura Exp $ */ 2 3/* 4 * Copyright (c) 1998, 1999 Tohru Nishimura. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Tohru Nishimura 17 * for the NetBSD Project. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 34 35__KERNEL_RCSID(0, "$NetBSD: xcfb.c,v 1.13 1999/11/29 07:50:55 nisimura Exp $"); 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/kernel.h> 40#include <sys/device.h> 41#include <sys/malloc.h> 42#include <sys/buf.h> 43#include <sys/ioctl.h> 44#include <vm/vm.h> 45 46#include <machine/bus.h> 47#include <machine/intr.h> 48 49#include <dev/rcons/raster.h> 50#include <dev/wscons/wsconsio.h> 51#include <dev/wscons/wscons_raster.h> 52#include <dev/wscons/wsdisplayvar.h> 53 54#include <dev/tc/tcvar.h> 55#include <dev/tc/ioasicreg.h> 56#include <dev/ic/ims332reg.h> 57#include <pmax/pmax/maxine.h> 58 59#include <uvm/uvm_extern.h> 60 61struct fb_devconfig { 62 vaddr_t dc_vaddr; /* memory space virtual base address */ 63 paddr_t dc_paddr; /* memory space physical base address */ 64 vsize_t dc_size; /* size of slot memory */ 65 int dc_wid; /* width of frame buffer */ 66 int dc_ht; /* height of frame buffer */ 67 int dc_depth; /* depth, bits per pixel */ 68 int dc_rowbytes; /* bytes in a FB scan line */ 69 vaddr_t dc_videobase; /* base of flat frame buffer */ 70 struct raster dc_raster; /* raster description */ 71 struct rcons dc_rcons; /* raster blitter control info */ 72 int dc_blanked; /* currently has video disabled */ 73}; 74 75struct hwcmap256 { 76#define CMAP_SIZE 256 /* 256 R/G/B entries */ 77 u_int8_t r[CMAP_SIZE]; 78 u_int8_t g[CMAP_SIZE]; 79 u_int8_t b[CMAP_SIZE]; 80}; 81 82struct hwcursor64 { 83 struct wsdisplay_curpos cc_pos; 84 struct wsdisplay_curpos cc_hot; 85 struct wsdisplay_curpos cc_size; 86 struct wsdisplay_curpos cc_magic; /* not used by PMAG-DV */ 87#define CURSOR_MAX_SIZE 64 88 u_int8_t cc_color[6]; 89 u_int64_t cc_image[64 + 64]; 90}; 91 92#define XCFB_FB_OFFSET 0x2000000 /* from module's base */ 93#define XCFB_FB_SIZE 0x100000 /* frame buffer size */ 94 95#define IMS332_HIGH (IOASIC_SLOT_5_START) 96#define IMS332_RLOW (IOASIC_SLOT_7_START) 97#define IMS332_WLOW (IOASIC_SLOT_7_START + 0x20000) 98 99struct xcfb_softc { 100 struct device sc_dev; 101 struct fb_devconfig *sc_dc; /* device configuration */ 102 struct hwcmap256 sc_cmap; /* software copy of colormap */ 103 struct hwcursor64 sc_cursor; /* software copy of cursor */ 104 /* XXX MAXINE can take PMAG-DV virtical retrace interrupt XXX */ 105 int nscreens; 106 /* cursor coordiate is located at upper-left corner */ 107 int sc_csr; /* software copy of IMS332 CSR A */ 108}; 109 110static int xcfbmatch __P((struct device *, struct cfdata *, void *)); 111static void xcfbattach __P((struct device *, struct device *, void *)); 112 113const struct cfattach xcfb_ca = { 114 sizeof(struct xcfb_softc), xcfbmatch, xcfbattach, 115}; 116 117static tc_addr_t xcfb_consaddr; 118static struct fb_devconfig xcfb_console_dc; 119static void xcfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *)); 120static void xcfbinit __P((struct fb_devconfig *)); 121int xcfb_cnattach __P((void)); 122 123static const struct wsdisplay_emulops xcfb_emulops = { 124 rcons_cursor, 125 rcons_mapchar, 126 rcons_putchar, 127 rcons_copycols, 128 rcons_erasecols, 129 rcons_copyrows, 130 rcons_eraserows, 131 rcons_alloc_attr 132}; 133 134struct wsscreen_descr xcfb_stdscreen = { 135 "std", 136 0, 0, /* will be filled in -- XXX shouldn't, it's global */ 137 &xcfb_emulops, 138 0, 0, 139 WSSCREEN_REVERSE 140}; 141 142static const struct wsscreen_descr *_xcfb_scrlist[] = { 143 &xcfb_stdscreen, 144}; 145 146static const struct wsscreen_list xcfb_screenlist = { 147 sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist 148}; 149 150static int xcfbioctl __P((void *, u_long, caddr_t, int, struct proc *)); 151static int xcfbmmap __P((void *, off_t, int)); 152 153static int xcfb_alloc_screen __P((void *, const struct wsscreen_descr *, 154 void **, int *, int *, long *)); 155static void xcfb_free_screen __P((void *, void *)); 156static void xcfb_show_screen __P((void *, void *)); 157 158static const struct wsdisplay_accessops xcfb_accessops = { 159 xcfbioctl, 160 xcfbmmap, 161 xcfb_alloc_screen, 162 xcfb_free_screen, 163 xcfb_show_screen, 164 0 /* load_font */ 165}; 166 167static int xcfbintr __P((void *)); 168static void xcfb_screenblank __P((struct xcfb_softc *)); 169static int set_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *)); 170static int get_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *)); 171static int set_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *)); 172static int get_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *)); 173static void set_curpos __P((struct xcfb_softc *, struct wsdisplay_curpos *)); 174static void ims332_loadcmap __P((struct hwcmap256 *)); 175static void ims332_set_curpos __P((struct xcfb_softc *)); 176static void ims332_load_curcmap __P((struct xcfb_softc *)); 177static void ims332_load_curshape __P((struct xcfb_softc *)); 178static void ims332_write_reg __P((int, u_int32_t)); 179#if 0 180static u_int32_t ims332_read_reg __P((int)); 181#endif 182 183extern long ioasic_base; /* XXX */ 184 185/* 186 * Compose 2 bit/pixel cursor image. 187 * M M M M I I I I M I M I M I M I 188 * [ before ] [ after ] 189 * 3 2 1 0 3 2 1 0 3 3 2 2 1 1 0 0 190 * 7 6 5 4 7 6 5 4 7 7 6 6 5 5 4 4 191 */ 192static const u_int8_t shuffle[256] = { 193 0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15, 194 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55, 195 0x02, 0x03, 0x06, 0x07, 0x12, 0x13, 0x16, 0x17, 196 0x42, 0x43, 0x46, 0x47, 0x52, 0x53, 0x56, 0x57, 197 0x08, 0x09, 0x0c, 0x0d, 0x18, 0x19, 0x1c, 0x1d, 198 0x48, 0x49, 0x4c, 0x4d, 0x58, 0x59, 0x5c, 0x5d, 199 0x0a, 0x0b, 0x0e, 0x0f, 0x1a, 0x1b, 0x1e, 0x1f, 200 0x4a, 0x4b, 0x4e, 0x4f, 0x5a, 0x5b, 0x5e, 0x5f, 201 0x20, 0x21, 0x24, 0x25, 0x30, 0x31, 0x34, 0x35, 202 0x60, 0x61, 0x64, 0x65, 0x70, 0x71, 0x74, 0x75, 203 0x22, 0x23, 0x26, 0x27, 0x32, 0x33, 0x36, 0x37, 204 0x62, 0x63, 0x66, 0x67, 0x72, 0x73, 0x76, 0x77, 205 0x28, 0x29, 0x2c, 0x2d, 0x38, 0x39, 0x3c, 0x3d, 206 0x68, 0x69, 0x6c, 0x6d, 0x78, 0x79, 0x7c, 0x7d, 207 0x2a, 0x2b, 0x2e, 0x2f, 0x3a, 0x3b, 0x3e, 0x3f, 208 0x6a, 0x6b, 0x6e, 0x6f, 0x7a, 0x7b, 0x7e, 0x7f, 209 0x80, 0x81, 0x84, 0x85, 0x90, 0x91, 0x94, 0x95, 210 0xc0, 0xc1, 0xc4, 0xc5, 0xd0, 0xd1, 0xd4, 0xd5, 211 0x82, 0x83, 0x86, 0x87, 0x92, 0x93, 0x96, 0x97, 212 0xc2, 0xc3, 0xc6, 0xc7, 0xd2, 0xd3, 0xd6, 0xd7, 213 0x88, 0x89, 0x8c, 0x8d, 0x98, 0x99, 0x9c, 0x9d, 214 0xc8, 0xc9, 0xcc, 0xcd, 0xd8, 0xd9, 0xdc, 0xdd, 215 0x8a, 0x8b, 0x8e, 0x8f, 0x9a, 0x9b, 0x9e, 0x9f, 216 0xca, 0xcb, 0xce, 0xcf, 0xda, 0xdb, 0xde, 0xdf, 217 0xa0, 0xa1, 0xa4, 0xa5, 0xb0, 0xb1, 0xb4, 0xb5, 218 0xe0, 0xe1, 0xe4, 0xe5, 0xf0, 0xf1, 0xf4, 0xf5, 219 0xa2, 0xa3, 0xa6, 0xa7, 0xb2, 0xb3, 0xb6, 0xb7, 220 0xe2, 0xe3, 0xe6, 0xe7, 0xf2, 0xf3, 0xf6, 0xf7, 221 0xa8, 0xa9, 0xac, 0xad, 0xb8, 0xb9, 0xbc, 0xbd, 222 0xe8, 0xe9, 0xec, 0xed, 0xf8, 0xf9, 0xfc, 0xfd, 223 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf, 224 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff, 225}; 226 227static int 228xcfbmatch(parent, match, aux) 229 struct device *parent; 230 struct cfdata *match; 231 void *aux; 232{ 233 struct tc_attach_args *ta = aux; 234 235 if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0) 236 return (0); 237 238 return (1); 239} 240 241static void 242xcfb_getdevconfig(dense_addr, dc) 243 tc_addr_t dense_addr; 244 struct fb_devconfig *dc; 245{ 246 struct raster *rap; 247 struct rcons *rcp; 248 int i; 249 250 dc->dc_vaddr = dense_addr; 251 dc->dc_paddr = MIPS_KSEG1_TO_PHYS(dc->dc_vaddr + XCFB_FB_OFFSET); 252 253 dc->dc_wid = 1024; 254 dc->dc_ht = 768; 255 dc->dc_depth = 8; 256 dc->dc_rowbytes = 1024; 257 dc->dc_videobase = dc->dc_vaddr + XCFB_FB_OFFSET; 258 dc->dc_blanked = 0; 259 260 /* initialize colormap and cursor resource */ 261 xcfbinit(dc); 262 263 /* clear the screen */ 264 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t)) 265 *(u_int32_t *)(dc->dc_videobase + i) = 0; 266 267 /* initialize the raster */ 268 rap = &dc->dc_raster; 269 rap->width = dc->dc_wid; 270 rap->height = dc->dc_ht; 271 rap->depth = dc->dc_depth; 272 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t); 273 rap->pixels = (u_int32_t *)dc->dc_videobase; 274 275 /* initialize the raster console blitter */ 276 rcp = &dc->dc_rcons; 277 rcp->rc_sp = rap; 278 rcp->rc_crow = rcp->rc_ccol = -1; 279 rcp->rc_crowp = &rcp->rc_crow; 280 rcp->rc_ccolp = &rcp->rc_ccol; 281 rcons_init(rcp, 34, 80); 282 283 xcfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow; 284 xcfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol; 285} 286 287static void 288xcfbattach(parent, self, aux) 289 struct device *parent, *self; 290 void *aux; 291{ 292 struct xcfb_softc *sc = (struct xcfb_softc *)self; 293 struct tc_attach_args *ta = aux; 294 struct wsemuldisplaydev_attach_args waa; 295 struct hwcmap256 *cm; 296 int console; 297 298 console = (ta->ta_addr == xcfb_consaddr); 299 if (console) { 300 sc->sc_dc = &xcfb_console_dc; 301 sc->nscreens = 1; 302 } 303 else { 304 sc->sc_dc = (struct fb_devconfig *) 305 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK); 306 xcfb_getdevconfig(ta->ta_addr, sc->sc_dc); 307 } 308 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht, 309 sc->sc_dc->dc_depth); 310 311 cm = &sc->sc_cmap; 312 memset(cm, 255, sizeof(struct hwcmap256)); /* XXX */ 313 cm->r[0] = cm->g[0] = cm->b[0] = 0; /* XXX */ 314 315 sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE; 316 317 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc); 318 319 waa.console = console; 320 waa.scrdata = &xcfb_screenlist; 321 waa.accessops = &xcfb_accessops; 322 waa.accesscookie = sc; 323 324 config_found(self, &waa, wsemuldisplaydevprint); 325} 326 327int 328xcfb_cnattach() 329{ 330 tc_addr_t addr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START); 331 struct fb_devconfig *dcp = &xcfb_console_dc; 332 long defattr; 333 334 xcfb_getdevconfig(addr, dcp); 335 336 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr); 337 338 wsdisplay_cnattach(&xcfb_stdscreen, &dcp->dc_rcons, 339 0, 0, defattr); 340 xcfb_consaddr = addr; 341 return (0); 342} 343 344static void 345xcfbinit(dc) 346 struct fb_devconfig *dc; 347{ 348 u_int32_t csr; 349 int i; 350 351 csr = *(u_int32_t *)(ioasic_base + IOASIC_CSR); 352 csr &= ~XINE_CSR_VDAC_ENABLE; 353 *(u_int32_t *)(ioasic_base + IOASIC_CSR) = csr; 354 DELAY(50); 355 csr |= XINE_CSR_VDAC_ENABLE; 356 *(u_int32_t *)(ioasic_base + IOASIC_CSR) = csr; 357 DELAY(50); 358 ims332_write_reg(IMS332_REG_BOOT, 0x2c); 359 ims332_write_reg(IMS332_REG_CSR_A, 360 IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR); 361 ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10); 362 ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21); 363 ims332_write_reg(IMS332_REG_DISPLAY, 0x100); 364 ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d); 365 ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f); 366 ims332_write_reg(IMS332_REG_LINE_TIME, 0x146); 367 ims332_write_reg(IMS332_REG_V_SYNC, 0x0c); 368 ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02); 369 ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02); 370 ims332_write_reg(IMS332_REG_V_BLANK, 0x2a); 371 ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600); 372 ims332_write_reg(IMS332_REG_LINE_START, 0x10); 373 ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a); 374 ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff); 375 ims332_write_reg(IMS332_REG_CSR_A, 376 IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE); 377 378 /* build sane colormap */ 379 ims332_write_reg(IMS332_REG_LUT_BASE, 0); 380 for (i = 1; i < CMAP_SIZE; i++) 381 ims332_write_reg(IMS332_REG_LUT_BASE + i, 0xffffff); 382 383 /* clear out cursor image */ 384 for (i = 0; i < 512; i++) 385 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0); 386 387 /* 388 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for 389 * cursor image. LUT_1 for mask color, while LUT_2 for 390 * image color. LUT_0 will be never used. 391 */ 392 ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0); 393 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff); 394 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff); 395} 396 397static int 398xcfbioctl(v, cmd, data, flag, p) 399 void *v; 400 u_long cmd; 401 caddr_t data; 402 int flag; 403 struct proc *p; 404{ 405 struct xcfb_softc *sc = v; 406 struct fb_devconfig *dc = sc->sc_dc; 407 int turnoff, error; 408 409 switch (cmd) { 410 case WSDISPLAYIO_GTYPE: 411 *(u_int *)data = WSDISPLAY_TYPE_XCFB; 412 return (0); 413 414 case WSDISPLAYIO_GINFO: 415#define wsd_fbip ((struct wsdisplay_fbinfo *)data) 416 wsd_fbip->height = sc->sc_dc->dc_ht; 417 wsd_fbip->width = sc->sc_dc->dc_wid; 418 wsd_fbip->depth = sc->sc_dc->dc_depth; 419 wsd_fbip->cmsize = CMAP_SIZE; 420#undef fbt 421 return (0); 422 423 case WSDISPLAYIO_GETCMAP: 424 return get_cmap(sc, (struct wsdisplay_cmap *)data); 425 426 case WSDISPLAYIO_PUTCMAP: 427 error = set_cmap(sc, (struct wsdisplay_cmap *)data); 428 if (error == 0) 429 ims332_loadcmap(&sc->sc_cmap); 430 return (error); 431 432 case WSDISPLAYIO_SVIDEO: 433 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 434 if ((dc->dc_blanked == 0) ^ turnoff) { 435 dc->dc_blanked = turnoff; 436 xcfb_screenblank(sc); 437 } 438 return (0); 439 440 case WSDISPLAYIO_GVIDEO: 441 *(u_int *)data = dc->dc_blanked ? 442 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 443 return (0); 444 445 case WSDISPLAYIO_GCURPOS: 446 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 447 return (0); 448 449 case WSDISPLAYIO_SCURPOS: 450 set_curpos(sc, (struct wsdisplay_curpos *)data); 451 ims332_set_curpos(sc); 452 return (0); 453 454 case WSDISPLAYIO_GCURMAX: 455 ((struct wsdisplay_curpos *)data)->x = 456 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 457 return (0); 458 459 case WSDISPLAYIO_GCURSOR: 460 return get_cursor(sc, (struct wsdisplay_cursor *)data); 461 462 case WSDISPLAYIO_SCURSOR: 463 return set_cursor(sc, (struct wsdisplay_cursor *)data); 464 } 465 return ENOTTY; 466} 467 468static int 469xcfbmmap(v, offset, prot) 470 void *v; 471 off_t offset; 472 int prot; 473{ 474 struct xcfb_softc *sc = v; 475 476 if (offset >= XCFB_FB_SIZE || offset < 0) 477 return -1; 478 return mips_btop(sc->sc_dc->dc_paddr + offset); 479} 480 481static int 482xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp) 483 void *v; 484 const struct wsscreen_descr *type; 485 void **cookiep; 486 int *curxp, *curyp; 487 long *attrp; 488{ 489 struct xcfb_softc *sc = v; 490 long defattr; 491 492 if (sc->nscreens > 0) 493 return (ENOMEM); 494 495 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */ 496 *curxp = 0; 497 *curyp = 0; 498 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr); 499 *attrp = defattr; 500 sc->nscreens++; 501 return (0); 502} 503 504static void 505xcfb_free_screen(v, cookie) 506 void *v; 507 void *cookie; 508{ 509 struct xcfb_softc *sc = v; 510 511 if (sc->sc_dc == &xcfb_console_dc) 512 panic("xcfb_free_screen: console"); 513 514 sc->nscreens--; 515} 516 517static void 518xcfb_show_screen(v, cookie) 519 void *v; 520 void *cookie; 521{ 522} 523 524static int 525xcfbintr(v) 526 void *v; 527{ 528 int intr; 529 530 intr = *(u_int32_t *)(ioasic_base + IOASIC_INTR); 531 intr &= ~XINE_INTR_VINT; 532 *(u_int32_t *)(ioasic_base + IOASIC_INTR) = intr; 533 return 1; 534} 535 536static void 537xcfb_screenblank(sc) 538 struct xcfb_softc *sc; 539{ 540 if (sc->sc_dc->dc_blanked) 541 sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK; 542 else 543 sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK; 544 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr); 545} 546 547static int 548get_cmap(sc, p) 549 struct xcfb_softc *sc; 550 struct wsdisplay_cmap *p; 551{ 552 u_int index = p->index, count = p->count; 553 554 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 555 return (EINVAL); 556 557 if (!uvm_useracc(p->red, count, B_WRITE) || 558 !uvm_useracc(p->green, count, B_WRITE) || 559 !uvm_useracc(p->blue, count, B_WRITE)) 560 return (EFAULT); 561 562 copyout(&sc->sc_cmap.r[index], p->red, count); 563 copyout(&sc->sc_cmap.g[index], p->green, count); 564 copyout(&sc->sc_cmap.b[index], p->blue, count); 565 566 return (0); 567} 568 569static int 570set_cmap(sc, p) 571 struct xcfb_softc *sc; 572 struct wsdisplay_cmap *p; 573{ 574 u_int index = p->index, count = p->count; 575 576 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE) 577 return (EINVAL); 578 579 if (!uvm_useracc(p->red, count, B_READ) || 580 !uvm_useracc(p->green, count, B_READ) || 581 !uvm_useracc(p->blue, count, B_READ)) 582 return (EFAULT); 583 584 copyin(p->red, &sc->sc_cmap.r[index], count); 585 copyin(p->green, &sc->sc_cmap.g[index], count); 586 copyin(p->blue, &sc->sc_cmap.b[index], count); 587 588 return (0); 589} 590 591static int 592set_cursor(sc, p) 593 struct xcfb_softc *sc; 594 struct wsdisplay_cursor *p; 595{ 596#define cc (&sc->sc_cursor) 597 int v, index, count; 598 599 v = p->which; 600 if (v & WSDISPLAY_CURSOR_DOCMAP) { 601 index = p->cmap.index; 602 count = p->cmap.count; 603 604 if (index >= 2 || index + count > 2) 605 return (EINVAL); 606 if (!uvm_useracc(p->cmap.red, count, B_READ) || 607 !uvm_useracc(p->cmap.green, count, B_READ) || 608 !uvm_useracc(p->cmap.blue, count, B_READ)) 609 return (EFAULT); 610 611 copyin(p->cmap.red, &cc->cc_color[index], count); 612 copyin(p->cmap.green, &cc->cc_color[index + 2], count); 613 copyin(p->cmap.blue, &cc->cc_color[index + 4], count); 614 ims332_load_curcmap(sc); 615 } 616 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 617 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 618 return (EINVAL); 619 count = ((p->size.x < 33) ? 4 : 8) * p->size.y; 620 if (!uvm_useracc(p->image, count, B_READ) || 621 !uvm_useracc(p->mask, count, B_READ)) 622 return (EFAULT); 623 cc->cc_size = p->size; 624 memset(cc->cc_image, 0, sizeof cc->cc_image); 625 copyin(p->image, cc->cc_image, count); 626 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count); 627 ims332_load_curshape(sc); 628 } 629 if (v & WSDISPLAY_CURSOR_DOCUR) { 630 cc->cc_hot = p->hot; 631 if (p->enable) 632 sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR; 633 else 634 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR; 635 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr); 636 } 637 if (v & WSDISPLAY_CURSOR_DOPOS) { 638 set_curpos(sc, &p->pos); 639 ims332_set_curpos(sc); 640 } 641 642 return (0); 643#undef cc 644} 645 646static int 647get_cursor(sc, p) 648 struct xcfb_softc *sc; 649 struct wsdisplay_cursor *p; 650{ 651 return (ENOTTY); /* XXX */ 652} 653 654static void 655set_curpos(sc, curpos) 656 struct xcfb_softc *sc; 657 struct wsdisplay_curpos *curpos; 658{ 659 struct fb_devconfig *dc = sc->sc_dc; 660 int x = curpos->x, y = curpos->y; 661 662 if (y < 0) 663 y = 0; 664 else if (y > dc->dc_ht) 665 y = dc->dc_ht; 666 if (x < 0) 667 x = 0; 668 else if (x > dc->dc_wid) 669 x = dc->dc_wid; 670 sc->sc_cursor.cc_pos.x = x; 671 sc->sc_cursor.cc_pos.y = y; 672} 673 674static void 675ims332_loadcmap(cm) 676 struct hwcmap256 *cm; 677{ 678 int i; 679 u_int32_t rgb; 680 681 for (i = 0; i < CMAP_SIZE; i++) { 682 rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i]; 683 ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb); 684 } 685} 686 687static void 688ims332_set_curpos(sc) 689 struct xcfb_softc *sc; 690{ 691 struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos; 692 u_int32_t pos; 693 int s; 694 695 s = spltty(); 696 pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff); 697 ims332_write_reg(IMS332_REG_CURSOR_LOC, pos); 698 splx(s); 699} 700 701static void 702ims332_load_curcmap(sc) 703 struct xcfb_softc *sc; 704{ 705 u_int8_t *cp = sc->sc_cursor.cc_color; 706 u_int32_t rgb; 707 708 /* cursor background */ 709 rgb = cp[5] << 16 | cp[3] << 8 | cp[1]; 710 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb); 711 712 /* cursor foreground */ 713 rgb = cp[4] << 16 | cp[2] << 8 | cp[0]; 714 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb); 715} 716 717static void 718ims332_load_curshape(sc) 719 struct xcfb_softc *sc; 720{ 721 unsigned i, img, msk, bits; 722 u_int8_t u, *ip, *mp; 723 724 ip = (u_int8_t *)sc->sc_cursor.cc_image; 725 mp = (u_int8_t *)(sc->sc_cursor.cc_image+CURSOR_MAX_SIZE); 726 727 i = 0; 728 /* 64 pixel scan line is consisted with 8 halfward cursor ram */ 729 while (i < sc->sc_cursor.cc_size.y * 8) { 730 /* pad right half 32 pixel when smaller than 33 */ 731 if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33) 732 bits = 0; 733 else { 734 img = *ip++; 735 msk = *mp++; 736 img &= msk; /* cookie off image */ 737 u = (msk & 0x0f) << 4 | (img & 0x0f); 738 bits = shuffle[u]; 739 u = (msk & 0xf0) | (img & 0xf0) >> 4; 740 bits = (shuffle[u] << 8) | bits; 741 } 742 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits); 743 i += 1; 744 } 745 /* pad unoccupied scan lines */ 746 while (i < CURSOR_MAX_SIZE * 8) { 747 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0); 748 i += 1; 749 } 750} 751 752static void 753ims332_write_reg(regno, val) 754 int regno; 755 u_int32_t val; 756{ 757 caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH); 758 caddr_t low16 = (caddr_t)(ioasic_base + IMS332_WLOW) + (regno << 4); 759 760 *(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8; 761 *(volatile u_int16_t *)low16 = val; 762} 763 764#if 0 765static u_int32_t 766ims332_read_reg(regno) 767 int regno; 768{ 769 caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH); 770 caddr_t low16 = (caddr_t)(ioasic_base + IMS332_RLOW) + (regno << 4); 771 u_int v0, v1; 772 773 v1 = *(volatile u_int16_t *)high8; 774 v0 = *(volatile u_int16_t *)low16; 775 return (v1 & 0xff00) << 8 | v0; 776} 777#endif 778