xcfb.c revision 1.56
1/* $NetBSD: xcfb.c,v 1.56 2018/01/24 05:35:58 riastradh 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.56 2018/01/24 05:35:58 riastradh 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 57struct 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 64struct 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 82struct 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 95static int xcfbmatch(device_t, cfdata_t, void *); 96static void xcfbattach(device_t, device_t, void *); 97 98CFATTACH_DECL_NEW(xcfb, sizeof(struct xcfb_softc), 99 xcfbmatch, xcfbattach, NULL, NULL); 100 101static tc_addr_t xcfb_consaddr; 102static struct rasops_info xcfb_console_ri; 103static void xcfb_common_init(struct rasops_info *); 104static void xcfbhwinit(void *); 105int xcfb_cnattach(void); 106 107struct wsscreen_descr xcfb_stdscreen = { 108 "std", 0, 0, 109 0, /* textops */ 110 0, 0, 111 WSSCREEN_REVERSE 112}; 113 114static const struct wsscreen_descr *_xcfb_scrlist[] = { 115 &xcfb_stdscreen, 116}; 117 118static const struct wsscreen_list xcfb_screenlist = { 119 sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist 120}; 121 122static int xcfbioctl(void *, void *, u_long, void *, int, struct lwp *); 123static paddr_t xcfbmmap(void *, void *, off_t, int); 124 125static int xcfb_alloc_screen(void *, const struct wsscreen_descr *, 126 void **, int *, int *, long *); 127static void xcfb_free_screen(void *, void *); 128static int xcfb_show_screen(void *, void *, int, 129 void (*) (void *, int, int), void *); 130 131static 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 140static int xcfbintr(void *); 141static void xcfb_screenblank(struct xcfb_softc *); 142static void xcfb_cmap_init(struct xcfb_softc *); 143static int set_cmap(struct xcfb_softc *, struct wsdisplay_cmap *); 144static int get_cmap(struct xcfb_softc *, struct wsdisplay_cmap *); 145static int set_cursor(struct xcfb_softc *, struct wsdisplay_cursor *); 146static int get_cursor(struct xcfb_softc *, struct wsdisplay_cursor *); 147static void set_curpos(struct xcfb_softc *, struct wsdisplay_curpos *); 148static void ims332_loadcmap(struct hwcmap256 *); 149static void ims332_set_curpos(struct xcfb_softc *); 150static void ims332_load_curcmap(struct xcfb_softc *); 151static void ims332_load_curshape(struct xcfb_softc *); 152static void ims332_write_reg(int, uint32_t); 153#if 0 154static uint32_t ims332_read_reg(int); 155#endif 156 157extern 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 */ 166static 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 201static int 202xcfbmatch(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 212static void 213xcfbattach(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_NOWAIT); 229 if (ri == NULL) { 230 printf(": can't alloc memory\n"); 231 return; 232 } 233 memset(ri, 0, sizeof(struct rasops_info)); 234 235 ri->ri_hw = (void *)ioasic_base; 236 xcfb_common_init(ri); 237 sc->sc_ri = ri; 238 } 239 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth); 240 241 xcfb_cmap_init(sc); 242 243 sc->sc_vaddr = ta->ta_addr; 244 sc->sc_blanked = 0; 245 sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE; 246 247 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc); 248 249 waa.console = console; 250 waa.scrdata = &xcfb_screenlist; 251 waa.accessops = &xcfb_accessops; 252 waa.accesscookie = sc; 253 254 config_found(self, &waa, wsemuldisplaydevprint); 255} 256 257static void 258xcfb_cmap_init(struct xcfb_softc *sc) 259{ 260 struct hwcmap256 *cm; 261 const uint8_t *p; 262 int index; 263 264 cm = &sc->sc_cmap; 265 p = rasops_cmap; 266 for (index = 0; index < CMAP_SIZE; index++, p += 3) { 267 cm->r[index] = p[0]; 268 cm->g[index] = p[1]; 269 cm->b[index] = p[2]; 270 } 271} 272 273static void 274xcfb_common_init(struct rasops_info *ri) 275{ 276 int cookie; 277 278 /* initialize colormap and cursor hardware */ 279 xcfbhwinit((void *)ri->ri_hw); 280 281 ri->ri_flg = RI_CENTER; 282 if (ri == &xcfb_console_ri) 283 ri->ri_flg |= RI_NO_AUTO; 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, WSFONT_FIND_BITMAP); 297 if (cookie <= 0) 298 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R, 299 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 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 320int 321xcfb_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 335static void 336xcfbhwinit(void *base) 337{ 338 volatile uint32_t *csr; 339 uint32_t i; 340 const uint8_t *p; 341 342 csr = (volatile uint32_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 uint32_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 393static int 394xcfbioctl(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 470static paddr_t 471xcfbmmap(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 479static int 480xcfb_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 499static void 500xcfb_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 510static int 511xcfb_show_screen(void *v, void *cookie, int waitok, 512 void (*cb)(void *, int, int), void *cbarg) 513{ 514 515 return (0); 516} 517 518static int 519xcfbintr(void *v) 520{ 521 struct xcfb_softc *sc = v; 522 uint32_t *intr, i; 523 524 intr = (uint32_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 531static void 532xcfb_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 541static int 542get_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 560static int 561set_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 585static int 586set_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 || count > 2 - index) 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 653static int 654get_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p) 655{ 656 return (EPASSTHROUGH); /* XXX */ 657} 658 659static void 660set_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 677static void 678ims332_loadcmap(struct hwcmap256 *cm) 679{ 680 int i; 681 uint32_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 689static void 690ims332_set_curpos(struct xcfb_softc *sc) 691{ 692 struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos; 693 uint32_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 702static void 703ims332_load_curcmap(struct xcfb_softc *sc) 704{ 705 uint8_t *cp = sc->sc_cursor.cc_color; 706 uint32_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 717static void 718ims332_load_curshape(struct xcfb_softc *sc) 719{ 720 u_int i, img, msk, bits; 721 uint8_t u, *ip, *mp; 722 723 ip = (uint8_t *)sc->sc_cursor.cc_image; 724 mp = (uint8_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 751static void 752ims332_write_reg(int regno, uint32_t val) 753{ 754 void *high8 = (void *)(ioasic_base + IMS332_HIGH); 755 void *low16 = (void *)(ioasic_base + IMS332_WLOW + (regno << 4)); 756 757 *(volatile uint16_t *)high8 = (val & 0xff0000) >> 8; 758 *(volatile uint16_t *)low16 = val; 759} 760 761#if 0 762static uint32_t 763ims332_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 uint16_t *)high8; 770 v0 = *(volatile uint16_t *)low16; 771 return (v1 & 0xff00) << 8 | v0; 772} 773#endif 774