xcfb.c revision 1.50
1/* $NetBSD: xcfb.c,v 1.50 2009/05/12 14:47:04 cegger 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.50 2009/05/12 14:47:04 cegger 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 59struct 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 66struct 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 84struct 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 97static int xcfbmatch(device_t, cfdata_t, void *); 98static void xcfbattach(device_t, device_t, void *); 99 100CFATTACH_DECL_NEW(xcfb, sizeof(struct xcfb_softc), 101 xcfbmatch, xcfbattach, NULL, NULL); 102 103static tc_addr_t xcfb_consaddr; 104static struct rasops_info xcfb_console_ri; 105static void xcfb_common_init(struct rasops_info *); 106static void xcfbhwinit(void *); 107int xcfb_cnattach(void); 108 109struct wsscreen_descr xcfb_stdscreen = { 110 "std", 0, 0, 111 0, /* textops */ 112 0, 0, 113 WSSCREEN_REVERSE 114}; 115 116static const struct wsscreen_descr *_xcfb_scrlist[] = { 117 &xcfb_stdscreen, 118}; 119 120static const struct wsscreen_list xcfb_screenlist = { 121 sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist 122}; 123 124static int xcfbioctl(void *, void *, u_long, void *, int, struct lwp *); 125static paddr_t xcfbmmap(void *, void *, off_t, int); 126 127static int xcfb_alloc_screen(void *, const struct wsscreen_descr *, 128 void **, int *, int *, long *); 129static void xcfb_free_screen(void *, void *); 130static int xcfb_show_screen(void *, void *, int, 131 void (*) (void *, int, int), void *); 132 133static 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 142static int xcfbintr(void *); 143static void xcfb_screenblank(struct xcfb_softc *); 144static void xcfb_cmap_init(struct xcfb_softc *); 145static int set_cmap(struct xcfb_softc *, struct wsdisplay_cmap *); 146static int get_cmap(struct xcfb_softc *, struct wsdisplay_cmap *); 147static int set_cursor(struct xcfb_softc *, struct wsdisplay_cursor *); 148static int get_cursor(struct xcfb_softc *, struct wsdisplay_cursor *); 149static void set_curpos(struct xcfb_softc *, struct wsdisplay_curpos *); 150static void ims332_loadcmap(struct hwcmap256 *); 151static void ims332_set_curpos(struct xcfb_softc *); 152static void ims332_load_curcmap(struct xcfb_softc *); 153static void ims332_load_curshape(struct xcfb_softc *); 154static void ims332_write_reg(int, u_int32_t); 155#if 0 156static u_int32_t ims332_read_reg(int); 157#endif 158 159extern 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 */ 168static 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 203static int 204xcfbmatch(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 214static void 215xcfbattach(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 ri = malloc(sizeof(struct rasops_info), M_DEVBUF, M_NOWAIT); 230 if (ri == NULL) { 231 printf(": can't alloc memory\n"); 232 return; 233 } 234 memset(ri, 0, sizeof(struct rasops_info)); 235 236 ri->ri_hw = (void *)ioasic_base; 237 xcfb_common_init(ri); 238 sc->sc_ri = ri; 239 } 240 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth); 241 242 xcfb_cmap_init(sc); 243 244 sc->sc_vaddr = ta->ta_addr; 245 sc->sc_blanked = 0; 246 sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE; 247 248 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc); 249 250 waa.console = console; 251 waa.scrdata = &xcfb_screenlist; 252 waa.accessops = &xcfb_accessops; 253 waa.accesscookie = sc; 254 255 config_found(self, &waa, wsemuldisplaydevprint); 256} 257 258static void 259xcfb_cmap_init(struct xcfb_softc *sc) 260{ 261 struct hwcmap256 *cm; 262 const u_int8_t *p; 263 int index; 264 265 cm = &sc->sc_cmap; 266 p = rasops_cmap; 267 for (index = 0; index < CMAP_SIZE; index++, p += 3) { 268 cm->r[index] = p[0]; 269 cm->g[index] = p[1]; 270 cm->b[index] = p[2]; 271 } 272} 273 274static void 275xcfb_common_init(struct rasops_info *ri) 276{ 277 int cookie; 278 279 /* initialize colormap and cursor hardware */ 280 xcfbhwinit((void *)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 = (void *)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(void) 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(void *base) 336{ 337 volatile u_int32_t *csr; 338 u_int32_t i; 339 const u_int8_t *p; 340 341 csr = (volatile u_int32_t *)((char *)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(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 394{ 395 struct xcfb_softc *sc = v; 396 struct rasops_info *ri = sc->sc_ri; 397 int turnoff, error; 398 399 switch (cmd) { 400 case WSDISPLAYIO_GTYPE: 401 *(u_int *)data = WSDISPLAY_TYPE_XCFB; 402 return (0); 403 404 case WSDISPLAYIO_GINFO: 405#define wsd_fbip ((struct wsdisplay_fbinfo *)data) 406 wsd_fbip->height = ri->ri_height; 407 wsd_fbip->width = ri->ri_width; 408 wsd_fbip->depth = ri->ri_depth; 409 wsd_fbip->cmsize = CMAP_SIZE; 410#undef fbt 411 return (0); 412 413 case WSDISPLAYIO_GETCMAP: 414 return get_cmap(sc, (struct wsdisplay_cmap *)data); 415 416 case WSDISPLAYIO_PUTCMAP: 417 error = set_cmap(sc, (struct wsdisplay_cmap *)data); 418 if (error == 0) 419 ims332_loadcmap(&sc->sc_cmap); 420 return (error); 421 422 case WSDISPLAYIO_SVIDEO: 423 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 424 if (sc->sc_blanked != turnoff) { 425 sc->sc_blanked = turnoff; 426 xcfb_screenblank(sc); 427 } 428 return (0); 429 430 case WSDISPLAYIO_GVIDEO: 431 *(u_int *)data = sc->sc_blanked ? 432 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 433 return (0); 434 435 case WSDISPLAYIO_GCURPOS: 436 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 437 return (0); 438 439 case WSDISPLAYIO_SCURPOS: 440 set_curpos(sc, (struct wsdisplay_curpos *)data); 441 ims332_set_curpos(sc); 442 return (0); 443 444 case WSDISPLAYIO_GCURMAX: 445 ((struct wsdisplay_curpos *)data)->x = 446 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 447 return (0); 448 449 case WSDISPLAYIO_GCURSOR: 450 return get_cursor(sc, (struct wsdisplay_cursor *)data); 451 452 case WSDISPLAYIO_SCURSOR: 453 return set_cursor(sc, (struct wsdisplay_cursor *)data); 454 455 case WSDISPLAYIO_SMODE: 456 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) { 457 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR; 458 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr); 459 xcfb_cmap_init(sc); 460 ims332_loadcmap(&sc->sc_cmap); 461 sc->sc_blanked = 0; 462 xcfb_screenblank(sc); 463 } 464 return (0); 465 } 466 return (EPASSTHROUGH); 467} 468 469static paddr_t 470xcfbmmap(void *v, void *vs, off_t offset, int prot) 471{ 472 473 if (offset >= XCFB_FB_SIZE || offset < 0) 474 return (-1); 475 return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset)); 476} 477 478static int 479xcfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 480 int *curxp, int *curyp, long *attrp) 481{ 482 struct xcfb_softc *sc = v; 483 struct rasops_info *ri = sc->sc_ri; 484 long defattr; 485 486 if (sc->nscreens > 0) 487 return (ENOMEM); 488 489 *cookiep = ri; /* one and only for now */ 490 *curxp = 0; 491 *curyp = 0; 492 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 493 *attrp = defattr; 494 sc->nscreens++; 495 return (0); 496} 497 498static void 499xcfb_free_screen(void *v, void *cookie) 500{ 501 struct xcfb_softc *sc = v; 502 503 if (sc->sc_ri == &xcfb_console_ri) 504 panic("xcfb_free_screen: console"); 505 506 sc->nscreens--; 507} 508 509static int 510xcfb_show_screen(void *v, void *cookie, int waitok, 511 void (*cb)(void *, int, int), void *cbarg) 512{ 513 514 return (0); 515} 516 517static int 518xcfbintr(void *v) 519{ 520 struct xcfb_softc *sc = v; 521 u_int32_t *intr, i; 522 523 intr = (u_int32_t *)((char *)sc->sc_ri->ri_hw + IOASIC_INTR); 524 i = *intr; 525 i &= ~XINE_INTR_VINT; 526 *intr = i; 527 return (1); 528} 529 530static void 531xcfb_screenblank(struct xcfb_softc *sc) 532{ 533 if (sc->sc_blanked) 534 sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK; 535 else 536 sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK; 537 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr); 538} 539 540static int 541get_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p) 542{ 543 u_int index = p->index, count = p->count; 544 int error; 545 546 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 547 return (EINVAL); 548 549 error = copyout(&sc->sc_cmap.r[index], p->red, count); 550 if (error) 551 return error; 552 error = copyout(&sc->sc_cmap.g[index], p->green, count); 553 if (error) 554 return error; 555 error = copyout(&sc->sc_cmap.b[index], p->blue, count); 556 return error; 557} 558 559static int 560set_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p) 561{ 562 struct hwcmap256 cmap; 563 u_int index = p->index, count = p->count; 564 int error; 565 566 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 567 return (EINVAL); 568 569 error = copyin(p->red, &cmap.r[index], count); 570 if (error) 571 return error; 572 error = copyin(p->green, &cmap.g[index], count); 573 if (error) 574 return error; 575 error = copyin(p->blue, &cmap.b[index], count); 576 if (error) 577 return error; 578 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count); 579 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count); 580 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count); 581 return (0); 582} 583 584static int 585set_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p) 586{ 587#define cc (&sc->sc_cursor) 588 u_int v, index = 0, count = 0, icount = 0; 589 uint8_t r[2], g[2], b[2], image[512], mask[512]; 590 int error; 591 592 v = p->which; 593 if (v & WSDISPLAY_CURSOR_DOCMAP) { 594 index = p->cmap.index; 595 count = p->cmap.count; 596 597 if (index >= 2 || index + count > 2) 598 return (EINVAL); 599 error = copyin(p->cmap.red, &r[index], count); 600 if (error) 601 return error; 602 error = copyin(p->cmap.green, &g[index], count); 603 if (error) 604 return error; 605 error = copyin(p->cmap.blue, &b[index], count); 606 if (error) 607 return error; 608 } 609 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 610 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 611 return (EINVAL); 612 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y; 613 error = copyin(p->image, image, icount); 614 if (error) 615 return error; 616 error = copyin(p->mask, mask, icount); 617 if (error) 618 return error; 619 } 620 621 if (v & WSDISPLAY_CURSOR_DOCMAP) { 622 memcpy(&cc->cc_color[index], &r[index], count); 623 memcpy(&cc->cc_color[index + 2], &g[index], count); 624 memcpy(&cc->cc_color[index + 4], &b[index], count); 625 ims332_load_curcmap(sc); 626 } 627 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 628 cc->cc_size = p->size; 629 memset(cc->cc_image, 0, sizeof cc->cc_image); 630 memcpy(cc->cc_image, image, icount); 631 memset(cc->cc_mask, 0, sizeof cc->cc_mask); 632 memcpy(cc->cc_mask, mask, icount); 633 ims332_load_curshape(sc); 634 } 635 if (v & WSDISPLAY_CURSOR_DOCUR) { 636 cc->cc_hot = p->hot; 637 if (p->enable) 638 sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR; 639 else 640 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR; 641 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr); 642 } 643 if (v & WSDISPLAY_CURSOR_DOPOS) { 644 set_curpos(sc, &p->pos); 645 ims332_set_curpos(sc); 646 } 647 648 return (0); 649#undef cc 650} 651 652static int 653get_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p) 654{ 655 return (EPASSTHROUGH); /* XXX */ 656} 657 658static void 659set_curpos(struct xcfb_softc *sc, struct wsdisplay_curpos *curpos) 660{ 661 struct rasops_info *ri = sc->sc_ri; 662 int x = curpos->x, y = curpos->y; 663 664 if (y < 0) 665 y = 0; 666 else if (y > ri->ri_height) 667 y = ri->ri_height; 668 if (x < 0) 669 x = 0; 670 else if (x > ri->ri_width) 671 x = ri->ri_width; 672 sc->sc_cursor.cc_pos.x = x; 673 sc->sc_cursor.cc_pos.y = y; 674} 675 676static void 677ims332_loadcmap(struct hwcmap256 *cm) 678{ 679 int i; 680 u_int32_t rgb; 681 682 for (i = 0; i < CMAP_SIZE; i++) { 683 rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i]; 684 ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb); 685 } 686} 687 688static void 689ims332_set_curpos(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(struct xcfb_softc *sc) 703{ 704 u_int8_t *cp = sc->sc_cursor.cc_color; 705 u_int32_t rgb; 706 707 /* cursor background */ 708 rgb = cp[5] << 16 | cp[3] << 8 | cp[1]; 709 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb); 710 711 /* cursor foreground */ 712 rgb = cp[4] << 16 | cp[2] << 8 | cp[0]; 713 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb); 714} 715 716static void 717ims332_load_curshape(struct xcfb_softc *sc) 718{ 719 u_int i, img, msk, bits; 720 u_int8_t u, *ip, *mp; 721 722 ip = (u_int8_t *)sc->sc_cursor.cc_image; 723 mp = (u_int8_t *)sc->sc_cursor.cc_mask; 724 725 i = 0; 726 /* 64 pixel scan line is consisted with 8 halfword cursor ram */ 727 while (i < sc->sc_cursor.cc_size.y * 8) { 728 /* pad right half 32 pixel when smaller than 33 */ 729 if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33) 730 bits = 0; 731 else { 732 img = *ip++; 733 msk = *mp++; 734 img &= msk; /* cookie off image */ 735 u = (msk & 0x0f) << 4 | (img & 0x0f); 736 bits = shuffle[u]; 737 u = (msk & 0xf0) | (img & 0xf0) >> 4; 738 bits = (shuffle[u] << 8) | bits; 739 } 740 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits); 741 i += 1; 742 } 743 /* pad unoccupied scan lines */ 744 while (i < CURSOR_MAX_SIZE * 8) { 745 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0); 746 i += 1; 747 } 748} 749 750static void 751ims332_write_reg(int regno, u_int32_t val) 752{ 753 void *high8 = (void *)(ioasic_base + IMS332_HIGH); 754 void *low16 = (void *)(ioasic_base + IMS332_WLOW + (regno << 4)); 755 756 *(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8; 757 *(volatile u_int16_t *)low16 = val; 758} 759 760#if 0 761static u_int32_t 762ims332_read_reg(int regno) 763{ 764 void *high8 = (void *)(ioasic_base + IMS332_HIGH); 765 void *low16 = (void *)(ioasic_base + IMS332_RLOW) + (regno << 4); 766 u_int v0, v1; 767 768 v1 = *(volatile u_int16_t *)high8; 769 v0 = *(volatile u_int16_t *)low16; 770 return (v1 & 0xff00) << 8 | v0; 771} 772#endif 773