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