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