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