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