xcfb.c revision 1.53
1/* $NetBSD: xcfb.c,v 1.53 2010/05/15 08:53:27 tsutsui 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.53 2010/05/15 08:53:27 tsutsui 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 uint8_t r[CMAP_SIZE]; 62 uint8_t g[CMAP_SIZE]; 63 uint8_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 uint8_t cc_color[6]; 73 uint64_t cc_image[CURSOR_MAX_SIZE]; 74 uint64_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, uint32_t); 155#if 0 156static uint32_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 uint8_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 ri->ri_flg &= ~RI_NO_AUTO; 227 sc->nscreens = 1; 228 } 229 else { 230 ri = malloc(sizeof(struct rasops_info), 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 259static void 260xcfb_cmap_init(struct xcfb_softc *sc) 261{ 262 struct hwcmap256 *cm; 263 const uint8_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 275static void 276xcfb_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 if (ri == &xcfb_console_ri) 285 ri->ri_flg |= RI_NO_AUTO; 286 ri->ri_depth = 8; 287 ri->ri_width = 1024; 288 ri->ri_height = 768; 289 ri->ri_stride = 1024; 290 ri->ri_bits = (void *)MIPS_PHYS_TO_KSEG1(XCFB_FB_BASE); 291 292 /* clear the screen */ 293 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height); 294 295 wsfont_init(); 296 /* prefer 12 pixel wide font */ 297 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R, 298 WSDISPLAY_FONTORDER_L2R); 299 if (cookie <= 0) 300 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R, 301 WSDISPLAY_FONTORDER_L2R); 302 if (cookie <= 0) { 303 printf("xcfb: font table is empty\n"); 304 return; 305 } 306 307 if (wsfont_lock(cookie, &ri->ri_font)) { 308 printf("xcfb: couldn't lock font\n"); 309 return; 310 } 311 ri->ri_wsfcookie = cookie; 312 313 rasops_init(ri, 34, 80); 314 315 /* XXX shouldn't be global */ 316 xcfb_stdscreen.nrows = ri->ri_rows; 317 xcfb_stdscreen.ncols = ri->ri_cols; 318 xcfb_stdscreen.textops = &ri->ri_ops; 319 xcfb_stdscreen.capabilities = ri->ri_caps; 320} 321 322int 323xcfb_cnattach(void) 324{ 325 struct rasops_info *ri; 326 long defattr; 327 328 ri = &xcfb_console_ri; 329 ri->ri_hw = (void *)ioasic_base; 330 xcfb_common_init(ri); 331 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 332 wsdisplay_cnattach(&xcfb_stdscreen, ri, 0, 0, defattr); 333 xcfb_consaddr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START); 334 return (0); 335} 336 337static void 338xcfbhwinit(void *base) 339{ 340 volatile uint32_t *csr; 341 uint32_t i; 342 const uint8_t *p; 343 344 csr = (volatile uint32_t *)((char *)base + IOASIC_CSR); 345 i = *csr; 346 i &= ~XINE_CSR_VDAC_ENABLE; 347 *csr = i; 348 DELAY(50); 349 i |= XINE_CSR_VDAC_ENABLE; 350 *csr = i; 351 DELAY(50); 352 ims332_write_reg(IMS332_REG_BOOT, 0x2c); 353 ims332_write_reg(IMS332_REG_CSR_A, 354 IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR); 355 ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10); 356 ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21); 357 ims332_write_reg(IMS332_REG_DISPLAY, 0x100); 358 ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d); 359 ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f); 360 ims332_write_reg(IMS332_REG_LINE_TIME, 0x146); 361 ims332_write_reg(IMS332_REG_V_SYNC, 0x0c); 362 ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02); 363 ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02); 364 ims332_write_reg(IMS332_REG_V_BLANK, 0x2a); 365 ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600); 366 ims332_write_reg(IMS332_REG_LINE_START, 0x10); 367 ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a); 368 ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff); 369 ims332_write_reg(IMS332_REG_CSR_A, 370 IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE); 371 372 /* build sane colormap */ 373 p = rasops_cmap; 374 for (i = 0; i < CMAP_SIZE; i++, p += 3) { 375 uint32_t bgr; 376 377 bgr = p[2] << 16 | p[1] << 8 | p[0]; 378 ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr); 379 } 380 381 /* clear out cursor image */ 382 for (i = 0; i < 512; i++) 383 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0); 384 385 /* 386 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for 387 * cursor image. LUT_1 for mask color, while LUT_2 for 388 * image color. LUT_0 will be never used. 389 */ 390 ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0); 391 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff); 392 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff); 393} 394 395static int 396xcfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 397{ 398 struct xcfb_softc *sc = v; 399 struct rasops_info *ri = sc->sc_ri; 400 int turnoff, error; 401 402 switch (cmd) { 403 case WSDISPLAYIO_GTYPE: 404 *(u_int *)data = WSDISPLAY_TYPE_XCFB; 405 return (0); 406 407 case WSDISPLAYIO_GINFO: 408#define wsd_fbip ((struct wsdisplay_fbinfo *)data) 409 wsd_fbip->height = ri->ri_height; 410 wsd_fbip->width = ri->ri_width; 411 wsd_fbip->depth = ri->ri_depth; 412 wsd_fbip->cmsize = CMAP_SIZE; 413#undef fbt 414 return (0); 415 416 case WSDISPLAYIO_GETCMAP: 417 return get_cmap(sc, (struct wsdisplay_cmap *)data); 418 419 case WSDISPLAYIO_PUTCMAP: 420 error = set_cmap(sc, (struct wsdisplay_cmap *)data); 421 if (error == 0) 422 ims332_loadcmap(&sc->sc_cmap); 423 return (error); 424 425 case WSDISPLAYIO_SVIDEO: 426 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 427 if (sc->sc_blanked != turnoff) { 428 sc->sc_blanked = turnoff; 429 xcfb_screenblank(sc); 430 } 431 return (0); 432 433 case WSDISPLAYIO_GVIDEO: 434 *(u_int *)data = sc->sc_blanked ? 435 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 436 return (0); 437 438 case WSDISPLAYIO_GCURPOS: 439 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 440 return (0); 441 442 case WSDISPLAYIO_SCURPOS: 443 set_curpos(sc, (struct wsdisplay_curpos *)data); 444 ims332_set_curpos(sc); 445 return (0); 446 447 case WSDISPLAYIO_GCURMAX: 448 ((struct wsdisplay_curpos *)data)->x = 449 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 450 return (0); 451 452 case WSDISPLAYIO_GCURSOR: 453 return get_cursor(sc, (struct wsdisplay_cursor *)data); 454 455 case WSDISPLAYIO_SCURSOR: 456 return set_cursor(sc, (struct wsdisplay_cursor *)data); 457 458 case WSDISPLAYIO_SMODE: 459 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) { 460 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR; 461 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr); 462 xcfb_cmap_init(sc); 463 ims332_loadcmap(&sc->sc_cmap); 464 sc->sc_blanked = 0; 465 xcfb_screenblank(sc); 466 } 467 return (0); 468 } 469 return (EPASSTHROUGH); 470} 471 472static paddr_t 473xcfbmmap(void *v, void *vs, off_t offset, int prot) 474{ 475 476 if (offset >= XCFB_FB_SIZE || offset < 0) 477 return (-1); 478 return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset)); 479} 480 481static int 482xcfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 483 int *curxp, int *curyp, long *attrp) 484{ 485 struct xcfb_softc *sc = v; 486 struct rasops_info *ri = sc->sc_ri; 487 long defattr; 488 489 if (sc->nscreens > 0) 490 return (ENOMEM); 491 492 *cookiep = ri; /* one and only for now */ 493 *curxp = 0; 494 *curyp = 0; 495 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 496 *attrp = defattr; 497 sc->nscreens++; 498 return (0); 499} 500 501static void 502xcfb_free_screen(void *v, 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(void *v, void *cookie, int waitok, 514 void (*cb)(void *, int, int), void *cbarg) 515{ 516 517 return (0); 518} 519 520static int 521xcfbintr(void *v) 522{ 523 struct xcfb_softc *sc = v; 524 uint32_t *intr, i; 525 526 intr = (uint32_t *)((char *)sc->sc_ri->ri_hw + IOASIC_INTR); 527 i = *intr; 528 i &= ~XINE_INTR_VINT; 529 *intr = i; 530 return (1); 531} 532 533static void 534xcfb_screenblank(struct xcfb_softc *sc) 535{ 536 if (sc->sc_blanked) 537 sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK; 538 else 539 sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK; 540 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr); 541} 542 543static int 544get_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p) 545{ 546 u_int index = p->index, count = p->count; 547 int error; 548 549 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 550 return (EINVAL); 551 552 error = copyout(&sc->sc_cmap.r[index], p->red, count); 553 if (error) 554 return error; 555 error = copyout(&sc->sc_cmap.g[index], p->green, count); 556 if (error) 557 return error; 558 error = copyout(&sc->sc_cmap.b[index], p->blue, count); 559 return error; 560} 561 562static int 563set_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p) 564{ 565 struct hwcmap256 cmap; 566 u_int index = p->index, count = p->count; 567 int error; 568 569 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 570 return (EINVAL); 571 572 error = copyin(p->red, &cmap.r[index], count); 573 if (error) 574 return error; 575 error = copyin(p->green, &cmap.g[index], count); 576 if (error) 577 return error; 578 error = copyin(p->blue, &cmap.b[index], count); 579 if (error) 580 return error; 581 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count); 582 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count); 583 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count); 584 return (0); 585} 586 587static int 588set_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p) 589{ 590#define cc (&sc->sc_cursor) 591 u_int v, index = 0, count = 0, icount = 0; 592 uint8_t r[2], g[2], b[2], image[512], mask[512]; 593 int error; 594 595 v = p->which; 596 if (v & WSDISPLAY_CURSOR_DOCMAP) { 597 index = p->cmap.index; 598 count = p->cmap.count; 599 600 if (index >= 2 || index + count > 2) 601 return (EINVAL); 602 error = copyin(p->cmap.red, &r[index], count); 603 if (error) 604 return error; 605 error = copyin(p->cmap.green, &g[index], count); 606 if (error) 607 return error; 608 error = copyin(p->cmap.blue, &b[index], count); 609 if (error) 610 return error; 611 } 612 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 613 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 614 return (EINVAL); 615 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y; 616 error = copyin(p->image, image, icount); 617 if (error) 618 return error; 619 error = copyin(p->mask, mask, icount); 620 if (error) 621 return error; 622 } 623 624 if (v & WSDISPLAY_CURSOR_DOCMAP) { 625 memcpy(&cc->cc_color[index], &r[index], count); 626 memcpy(&cc->cc_color[index + 2], &g[index], count); 627 memcpy(&cc->cc_color[index + 4], &b[index], count); 628 ims332_load_curcmap(sc); 629 } 630 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 631 cc->cc_size = p->size; 632 memset(cc->cc_image, 0, sizeof cc->cc_image); 633 memcpy(cc->cc_image, image, icount); 634 memset(cc->cc_mask, 0, sizeof cc->cc_mask); 635 memcpy(cc->cc_mask, mask, icount); 636 ims332_load_curshape(sc); 637 } 638 if (v & WSDISPLAY_CURSOR_DOCUR) { 639 cc->cc_hot = p->hot; 640 if (p->enable) 641 sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR; 642 else 643 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR; 644 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr); 645 } 646 if (v & WSDISPLAY_CURSOR_DOPOS) { 647 set_curpos(sc, &p->pos); 648 ims332_set_curpos(sc); 649 } 650 651 return (0); 652#undef cc 653} 654 655static int 656get_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p) 657{ 658 return (EPASSTHROUGH); /* XXX */ 659} 660 661static void 662set_curpos(struct xcfb_softc *sc, struct wsdisplay_curpos *curpos) 663{ 664 struct rasops_info *ri = sc->sc_ri; 665 int x = curpos->x, y = curpos->y; 666 667 if (y < 0) 668 y = 0; 669 else if (y > ri->ri_height) 670 y = ri->ri_height; 671 if (x < 0) 672 x = 0; 673 else if (x > ri->ri_width) 674 x = ri->ri_width; 675 sc->sc_cursor.cc_pos.x = x; 676 sc->sc_cursor.cc_pos.y = y; 677} 678 679static void 680ims332_loadcmap(struct hwcmap256 *cm) 681{ 682 int i; 683 uint32_t rgb; 684 685 for (i = 0; i < CMAP_SIZE; i++) { 686 rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i]; 687 ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb); 688 } 689} 690 691static void 692ims332_set_curpos(struct xcfb_softc *sc) 693{ 694 struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos; 695 uint32_t pos; 696 int s; 697 698 s = spltty(); 699 pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff); 700 ims332_write_reg(IMS332_REG_CURSOR_LOC, pos); 701 splx(s); 702} 703 704static void 705ims332_load_curcmap(struct xcfb_softc *sc) 706{ 707 uint8_t *cp = sc->sc_cursor.cc_color; 708 uint32_t rgb; 709 710 /* cursor background */ 711 rgb = cp[5] << 16 | cp[3] << 8 | cp[1]; 712 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb); 713 714 /* cursor foreground */ 715 rgb = cp[4] << 16 | cp[2] << 8 | cp[0]; 716 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb); 717} 718 719static void 720ims332_load_curshape(struct xcfb_softc *sc) 721{ 722 u_int i, img, msk, bits; 723 uint8_t u, *ip, *mp; 724 725 ip = (uint8_t *)sc->sc_cursor.cc_image; 726 mp = (uint8_t *)sc->sc_cursor.cc_mask; 727 728 i = 0; 729 /* 64 pixel scan line is consisted with 8 halfword cursor ram */ 730 while (i < sc->sc_cursor.cc_size.y * 8) { 731 /* pad right half 32 pixel when smaller than 33 */ 732 if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33) 733 bits = 0; 734 else { 735 img = *ip++; 736 msk = *mp++; 737 img &= msk; /* cookie off image */ 738 u = (msk & 0x0f) << 4 | (img & 0x0f); 739 bits = shuffle[u]; 740 u = (msk & 0xf0) | (img & 0xf0) >> 4; 741 bits = (shuffle[u] << 8) | bits; 742 } 743 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits); 744 i += 1; 745 } 746 /* pad unoccupied scan lines */ 747 while (i < CURSOR_MAX_SIZE * 8) { 748 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0); 749 i += 1; 750 } 751} 752 753static void 754ims332_write_reg(int regno, uint32_t val) 755{ 756 void *high8 = (void *)(ioasic_base + IMS332_HIGH); 757 void *low16 = (void *)(ioasic_base + IMS332_WLOW + (regno << 4)); 758 759 *(volatile uint16_t *)high8 = (val & 0xff0000) >> 8; 760 *(volatile uint16_t *)low16 = val; 761} 762 763#if 0 764static uint32_t 765ims332_read_reg(int regno) 766{ 767 void *high8 = (void *)(ioasic_base + IMS332_HIGH); 768 void *low16 = (void *)(ioasic_base + IMS332_RLOW) + (regno << 4); 769 u_int v0, v1; 770 771 v1 = *(volatile uint16_t *)high8; 772 v0 = *(volatile uint16_t *)low16; 773 return (v1 & 0xff00) << 8 | v0; 774} 775#endif 776