xcfb.c revision 1.46
119370Spst/* $NetBSD: xcfb.c,v 1.46 2008/05/26 10:31:22 nisimura Exp $ */ 298944Sobrien 398944Sobrien/*- 419370Spst * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc. 598944Sobrien * All rights reserved. 619370Spst * 798944Sobrien * This code is derived from software contributed to The NetBSD Foundation 898944Sobrien * by Tohru Nishimura. 998944Sobrien * 1098944Sobrien * Redistribution and use in source and binary forms, with or without 1119370Spst * modification, are permitted provided that the following conditions 1298944Sobrien * are met: 1398944Sobrien * 1. Redistributions of source code must retain the above copyright 1498944Sobrien * notice, this list of conditions and the following disclaimer. 1598944Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1619370Spst * notice, this list of conditions and the following disclaimer in the 1798944Sobrien * documentation and/or other materials provided with the distribution. 1898944Sobrien * 1998944Sobrien * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2098944Sobrien * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2119370Spst * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2219370Spst * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2319370Spst * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2419370Spst * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25130803Smarcel * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26130803Smarcel * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2798944Sobrien * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2898944Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2919370Spst * POSSIBILITY OF SUCH DAMAGE. 3098944Sobrien */ 3198944Sobrien 3219370Spst#include <sys/cdefs.h> 3398944Sobrien__KERNEL_RCSID(0, "$NetBSD: xcfb.c,v 1.46 2008/05/26 10:31:22 nisimura Exp $"); 3498944Sobrien 3519370Spst#include <sys/param.h> 3698944Sobrien#include <sys/systm.h> 3798944Sobrien#include <sys/kernel.h> 3898944Sobrien#include <sys/device.h> 3998944Sobrien#include <sys/malloc.h> 4098944Sobrien#include <sys/buf.h> 4119370Spst#include <sys/ioctl.h> 4298944Sobrien 4319370Spst#include <sys/bus.h> 4498944Sobrien#include <sys/intr.h> 4519370Spst 4698944Sobrien#include <dev/wscons/wsconsio.h> 4719370Spst#include <dev/wscons/wsdisplayvar.h> 4898944Sobrien 4919370Spst#include <dev/rasops/rasops.h> 5098944Sobrien#include <dev/wsfont/wsfont.h> 5119370Spst 5298944Sobrien#include <dev/tc/tcvar.h> 5319370Spst#include <dev/tc/ioasicreg.h> 5498944Sobrien#include <dev/ic/ims332reg.h> 5519370Spst#include <pmax/pmax/maxine.h> 5698944Sobrien 5798944Sobrien#include <uvm/uvm_extern.h> 5898944Sobrien 5998944Sobrienstruct hwcmap256 { 6098944Sobrien#define CMAP_SIZE 256 /* 256 R/G/B entries */ 6119370Spst u_int8_t r[CMAP_SIZE]; 6298944Sobrien u_int8_t g[CMAP_SIZE]; 6398944Sobrien u_int8_t b[CMAP_SIZE]; 6498944Sobrien}; 6598944Sobrien 6698944Sobrienstruct hwcursor64 { 6798944Sobrien struct wsdisplay_curpos cc_pos; 6898944Sobrien struct wsdisplay_curpos cc_hot; 6998944Sobrien struct wsdisplay_curpos cc_size; 7098944Sobrien struct wsdisplay_curpos cc_magic; /* not used by PMAG-DV */ 7119370Spst#define CURSOR_MAX_SIZE 64 7298944Sobrien u_int8_t cc_color[6]; 7319370Spst u_int64_t cc_image[CURSOR_MAX_SIZE]; 7498944Sobrien u_int64_t cc_mask[CURSOR_MAX_SIZE]; 7598944Sobrien}; 7698944Sobrien 7798944Sobrien#define XCFB_FB_BASE (XINE_PHYS_CFB_START + 0x2000000) 7898944Sobrien#define XCFB_FB_SIZE 0x100000 7998944Sobrien 8098944Sobrien#define IMS332_HIGH (IOASIC_SLOT_5_START) 8198944Sobrien#define IMS332_RLOW (IOASIC_SLOT_7_START) 8298944Sobrien#define IMS332_WLOW (IOASIC_SLOT_7_START + 0x20000) 8346283Sdfr 8446283Sdfrstruct xcfb_softc { 8598944Sobrien struct device sc_dev; 8619370Spst vaddr_t sc_vaddr; 8798944Sobrien size_t sc_size; 8898944Sobrien struct rasops_info *sc_ri; 8919370Spst struct hwcmap256 sc_cmap; /* software copy of colormap */ 9098944Sobrien struct hwcursor64 sc_cursor; /* software copy of cursor */ 9119370Spst int sc_blanked; 9298944Sobrien /* XXX MAXINE can take PMAG-DV vertical retrace interrupt XXX */ 9398944Sobrien int nscreens; 9419370Spst /* cursor coordinate is located at upper-left corner */ 9598944Sobrien int sc_csr; /* software copy of IMS332 CSR A */ 9698944Sobrien}; 9719370Spst 9819370Spststatic int xcfbmatch(struct device *, struct cfdata *, void *); 9998944Sobrienstatic void xcfbattach(struct device *, struct device *, void *); 10019370Spst 10119370SpstCFATTACH_DECL(xcfb, sizeof(struct xcfb_softc), 10219370Spst xcfbmatch, xcfbattach, NULL, NULL); 10398944Sobrien 10419370Spststatic tc_addr_t xcfb_consaddr; 10519370Spststatic struct rasops_info xcfb_console_ri; 10619370Spststatic void xcfb_common_init(struct rasops_info *); 10719370Spststatic void xcfbhwinit(void *); 10898944Sobrienint xcfb_cnattach(void); 10998944Sobrien 11019370Spststruct wsscreen_descr xcfb_stdscreen = { 11119370Spst "std", 0, 0, 11298944Sobrien 0, /* textops */ 11398944Sobrien 0, 0, 11419370Spst WSSCREEN_REVERSE 11598944Sobrien}; 11619370Spst 11798944Sobrienstatic const struct wsscreen_descr *_xcfb_scrlist[] = { 11898944Sobrien &xcfb_stdscreen, 11998944Sobrien}; 12098944Sobrien 12198944Sobrienstatic const struct wsscreen_list xcfb_screenlist = { 12298944Sobrien sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist 12319370Spst}; 12419370Spst 12598944Sobrienstatic int xcfbioctl(void *, void *, u_long, void *, int, struct lwp *); 12698944Sobrienstatic paddr_t xcfbmmap(void *, void *, off_t, int); 12798944Sobrien 12819370Spststatic int xcfb_alloc_screen(void *, const struct wsscreen_descr *, 12998944Sobrien void **, int *, int *, long *); 13019370Spststatic void xcfb_free_screen(void *, void *); 13198944Sobrienstatic int xcfb_show_screen(void *, void *, int, 13298944Sobrien void (*) (void *, int, int), void *); 13319370Spst 13498944Sobrienstatic const struct wsdisplay_accessops xcfb_accessops = { 13519370Spst xcfbioctl, 13698944Sobrien xcfbmmap, 13798944Sobrien xcfb_alloc_screen, 13819370Spst xcfb_free_screen, 13998944Sobrien xcfb_show_screen, 14098944Sobrien 0 /* load_font */ 14198944Sobrien}; 14219370Spst 14398944Sobrienstatic int xcfbintr(void *); 14419370Spststatic void xcfb_screenblank(struct xcfb_softc *); 14598944Sobrienstatic void xcfb_cmap_init(struct xcfb_softc *); 14619370Spststatic int set_cmap(struct xcfb_softc *, struct wsdisplay_cmap *); 14798944Sobrienstatic int get_cmap(struct xcfb_softc *, struct wsdisplay_cmap *); 14819370Spststatic int set_cursor(struct xcfb_softc *, struct wsdisplay_cursor *); 14998944Sobrienstatic int get_cursor(struct xcfb_softc *, struct wsdisplay_cursor *); 15019370Spststatic void set_curpos(struct xcfb_softc *, struct wsdisplay_curpos *); 15198944Sobrienstatic void ims332_loadcmap(struct hwcmap256 *); 15219370Spststatic void ims332_set_curpos(struct xcfb_softc *); 15398944Sobrienstatic void ims332_load_curcmap(struct xcfb_softc *); 15419370Spststatic void ims332_load_curshape(struct xcfb_softc *); 15598944Sobrienstatic void ims332_write_reg(int, u_int32_t); 15698944Sobrien#if 0 15798944Sobrienstatic u_int32_t ims332_read_reg(int); 15819370Spst#endif 15998944Sobrien 16098944Sobrienextern long ioasic_base; /* XXX */ 16119370Spst 16298944Sobrien/* 16398944Sobrien * Compose 2 bit/pixel cursor image. 16498944Sobrien * M M M M I I I I M I M I M I M I 16598944Sobrien * [ before ] [ after ] 16619370Spst * 3 2 1 0 3 2 1 0 3 3 2 2 1 1 0 0 16798944Sobrien * 7 6 5 4 7 6 5 4 7 7 6 6 5 5 4 4 16819370Spst */ 16998944Sobrienstatic const u_int8_t shuffle[256] = { 17019370Spst 0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15, 17198944Sobrien 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55, 17298944Sobrien 0x02, 0x03, 0x06, 0x07, 0x12, 0x13, 0x16, 0x17, 17319370Spst 0x42, 0x43, 0x46, 0x47, 0x52, 0x53, 0x56, 0x57, 17498944Sobrien 0x08, 0x09, 0x0c, 0x0d, 0x18, 0x19, 0x1c, 0x1d, 17519370Spst 0x48, 0x49, 0x4c, 0x4d, 0x58, 0x59, 0x5c, 0x5d, 17698944Sobrien 0x0a, 0x0b, 0x0e, 0x0f, 0x1a, 0x1b, 0x1e, 0x1f, 17798944Sobrien 0x4a, 0x4b, 0x4e, 0x4f, 0x5a, 0x5b, 0x5e, 0x5f, 17898944Sobrien 0x20, 0x21, 0x24, 0x25, 0x30, 0x31, 0x34, 0x35, 17998944Sobrien 0x60, 0x61, 0x64, 0x65, 0x70, 0x71, 0x74, 0x75, 18098944Sobrien 0x22, 0x23, 0x26, 0x27, 0x32, 0x33, 0x36, 0x37, 18198944Sobrien 0x62, 0x63, 0x66, 0x67, 0x72, 0x73, 0x76, 0x77, 18298944Sobrien 0x28, 0x29, 0x2c, 0x2d, 0x38, 0x39, 0x3c, 0x3d, 18398944Sobrien 0x68, 0x69, 0x6c, 0x6d, 0x78, 0x79, 0x7c, 0x7d, 18498944Sobrien 0x2a, 0x2b, 0x2e, 0x2f, 0x3a, 0x3b, 0x3e, 0x3f, 18598944Sobrien 0x6a, 0x6b, 0x6e, 0x6f, 0x7a, 0x7b, 0x7e, 0x7f, 18698944Sobrien 0x80, 0x81, 0x84, 0x85, 0x90, 0x91, 0x94, 0x95, 18798944Sobrien 0xc0, 0xc1, 0xc4, 0xc5, 0xd0, 0xd1, 0xd4, 0xd5, 18898944Sobrien 0x82, 0x83, 0x86, 0x87, 0x92, 0x93, 0x96, 0x97, 18998944Sobrien 0xc2, 0xc3, 0xc6, 0xc7, 0xd2, 0xd3, 0xd6, 0xd7, 19098944Sobrien 0x88, 0x89, 0x8c, 0x8d, 0x98, 0x99, 0x9c, 0x9d, 19198944Sobrien 0xc8, 0xc9, 0xcc, 0xcd, 0xd8, 0xd9, 0xdc, 0xdd, 19298944Sobrien 0x8a, 0x8b, 0x8e, 0x8f, 0x9a, 0x9b, 0x9e, 0x9f, 19398944Sobrien 0xca, 0xcb, 0xce, 0xcf, 0xda, 0xdb, 0xde, 0xdf, 19498944Sobrien 0xa0, 0xa1, 0xa4, 0xa5, 0xb0, 0xb1, 0xb4, 0xb5, 19598944Sobrien 0xe0, 0xe1, 0xe4, 0xe5, 0xf0, 0xf1, 0xf4, 0xf5, 19698944Sobrien 0xa2, 0xa3, 0xa6, 0xa7, 0xb2, 0xb3, 0xb6, 0xb7, 19798944Sobrien 0xe2, 0xe3, 0xe6, 0xe7, 0xf2, 0xf3, 0xf6, 0xf7, 19898944Sobrien 0xa8, 0xa9, 0xac, 0xad, 0xb8, 0xb9, 0xbc, 0xbd, 19998944Sobrien 0xe8, 0xe9, 0xec, 0xed, 0xf8, 0xf9, 0xfc, 0xfd, 20098944Sobrien 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf, 20198944Sobrien 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff, 20298944Sobrien}; 20398944Sobrien 20498944Sobrienstatic int 20598944Sobrienxcfbmatch(struct device *parent, struct cfdata *match, void *aux) 20698944Sobrien{ 20798944Sobrien struct tc_attach_args *ta = aux; 20898944Sobrien 20998944Sobrien if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0) 21098944Sobrien return (0); 21198944Sobrien 21298944Sobrien return (1); 21398944Sobrien} 21498944Sobrien 21598944Sobrienstatic void 21698944Sobrienxcfbattach(struct device *parent, struct device *self, void *aux) 21798944Sobrien{ 21898944Sobrien struct xcfb_softc *sc = device_private(self); 21998944Sobrien struct tc_attach_args *ta = aux; 22098944Sobrien struct rasops_info *ri; 22198944Sobrien struct wsemuldisplaydev_attach_args waa; 22298944Sobrien int console; 22398944Sobrien 22498944Sobrien console = (ta->ta_addr == xcfb_consaddr); 22598944Sobrien if (console) { 22698944Sobrien sc->sc_ri = ri = &xcfb_console_ri; 22798944Sobrien sc->nscreens = 1; 22898944Sobrien } 22998944Sobrien else { 23098944Sobrien MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info), 23198944Sobrien M_DEVBUF, M_NOWAIT); 23298944Sobrien if (ri == NULL) { 23398944Sobrien printf(": can't alloc memory\n"); 23498944Sobrien return; 23598944Sobrien } 23698944Sobrien memset(ri, 0, sizeof(struct rasops_info)); 23798944Sobrien 23898944Sobrien ri->ri_hw = (void *)ioasic_base; 23919370Spst xcfb_common_init(ri); 24019370Spst sc->sc_ri = ri; 24198944Sobrien } 24219370Spst printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth); 24319370Spst 244 xcfb_cmap_init(sc); 245 246 sc->sc_vaddr = ta->ta_addr; 247 sc->sc_blanked = 0; 248 sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE; 249 250 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc); 251 252 waa.console = console; 253 waa.scrdata = &xcfb_screenlist; 254 waa.accessops = &xcfb_accessops; 255 waa.accesscookie = sc; 256 257 config_found(self, &waa, wsemuldisplaydevprint); 258} 259 260static void 261xcfb_cmap_init(struct xcfb_softc *sc) 262{ 263 struct hwcmap256 *cm; 264 const u_int8_t *p; 265 int index; 266 267 cm = &sc->sc_cmap; 268 p = rasops_cmap; 269 for (index = 0; index < CMAP_SIZE; index++, p += 3) { 270 cm->r[index] = p[0]; 271 cm->g[index] = p[1]; 272 cm->b[index] = p[2]; 273 } 274} 275 276static void 277xcfb_common_init(struct rasops_info *ri) 278{ 279 int cookie; 280 281 /* initialize colormap and cursor hardware */ 282 xcfbhwinit((void *)ri->ri_hw); 283 284 ri->ri_flg = RI_CENTER; 285 ri->ri_depth = 8; 286 ri->ri_width = 1024; 287 ri->ri_height = 768; 288 ri->ri_stride = 1024; 289 ri->ri_bits = (void *)MIPS_PHYS_TO_KSEG1(XCFB_FB_BASE); 290 291 /* clear the screen */ 292 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height); 293 294 wsfont_init(); 295 /* prefer 12 pixel wide font */ 296 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R, 297 WSDISPLAY_FONTORDER_L2R); 298 if (cookie <= 0) 299 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R, 300 WSDISPLAY_FONTORDER_L2R); 301 if (cookie <= 0) { 302 printf("xcfb: font table is empty\n"); 303 return; 304 } 305 306 if (wsfont_lock(cookie, &ri->ri_font)) { 307 printf("xcfb: couldn't lock font\n"); 308 return; 309 } 310 ri->ri_wsfcookie = cookie; 311 312 rasops_init(ri, 34, 80); 313 314 /* XXX shouldn't be global */ 315 xcfb_stdscreen.nrows = ri->ri_rows; 316 xcfb_stdscreen.ncols = ri->ri_cols; 317 xcfb_stdscreen.textops = &ri->ri_ops; 318 xcfb_stdscreen.capabilities = ri->ri_caps; 319} 320 321int 322xcfb_cnattach(void) 323{ 324 struct rasops_info *ri; 325 long defattr; 326 327 ri = &xcfb_console_ri; 328 ri->ri_hw = (void *)ioasic_base; 329 xcfb_common_init(ri); 330 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 331 wsdisplay_cnattach(&xcfb_stdscreen, ri, 0, 0, defattr); 332 xcfb_consaddr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START); 333 return (0); 334} 335 336static void 337xcfbhwinit(void *base) 338{ 339 volatile u_int32_t *csr; 340 u_int32_t i; 341 const u_int8_t *p; 342 343 csr = (volatile u_int32_t *)((char *)base + IOASIC_CSR); 344 i = *csr; 345 i &= ~XINE_CSR_VDAC_ENABLE; 346 *csr = i; 347 DELAY(50); 348 i |= XINE_CSR_VDAC_ENABLE; 349 *csr = i; 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 p = rasops_cmap; 373 for (i = 0; i < CMAP_SIZE; i++, p += 3) { 374 u_int32_t bgr; 375 376 bgr = p[2] << 16 | p[1] << 8 | p[0]; 377 ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr); 378 } 379 380 /* clear out cursor image */ 381 for (i = 0; i < 512; i++) 382 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0); 383 384 /* 385 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for 386 * cursor image. LUT_1 for mask color, while LUT_2 for 387 * image color. LUT_0 will be never used. 388 */ 389 ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0); 390 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff); 391 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff); 392} 393 394static int 395xcfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 396{ 397 struct xcfb_softc *sc = v; 398 struct rasops_info *ri = sc->sc_ri; 399 int turnoff, error; 400 401 switch (cmd) { 402 case WSDISPLAYIO_GTYPE: 403 *(u_int *)data = WSDISPLAY_TYPE_XCFB; 404 return (0); 405 406 case WSDISPLAYIO_GINFO: 407#define wsd_fbip ((struct wsdisplay_fbinfo *)data) 408 wsd_fbip->height = ri->ri_height; 409 wsd_fbip->width = ri->ri_width; 410 wsd_fbip->depth = ri->ri_depth; 411 wsd_fbip->cmsize = CMAP_SIZE; 412#undef fbt 413 return (0); 414 415 case WSDISPLAYIO_GETCMAP: 416 return get_cmap(sc, (struct wsdisplay_cmap *)data); 417 418 case WSDISPLAYIO_PUTCMAP: 419 error = set_cmap(sc, (struct wsdisplay_cmap *)data); 420 if (error == 0) 421 ims332_loadcmap(&sc->sc_cmap); 422 return (error); 423 424 case WSDISPLAYIO_SVIDEO: 425 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF; 426 if (sc->sc_blanked != turnoff) { 427 sc->sc_blanked = turnoff; 428 xcfb_screenblank(sc); 429 } 430 return (0); 431 432 case WSDISPLAYIO_GVIDEO: 433 *(u_int *)data = sc->sc_blanked ? 434 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON; 435 return (0); 436 437 case WSDISPLAYIO_GCURPOS: 438 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 439 return (0); 440 441 case WSDISPLAYIO_SCURPOS: 442 set_curpos(sc, (struct wsdisplay_curpos *)data); 443 ims332_set_curpos(sc); 444 return (0); 445 446 case WSDISPLAYIO_GCURMAX: 447 ((struct wsdisplay_curpos *)data)->x = 448 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 449 return (0); 450 451 case WSDISPLAYIO_GCURSOR: 452 return get_cursor(sc, (struct wsdisplay_cursor *)data); 453 454 case WSDISPLAYIO_SCURSOR: 455 return set_cursor(sc, (struct wsdisplay_cursor *)data); 456 457 case WSDISPLAYIO_SMODE: 458 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) { 459 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR; 460 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr); 461 xcfb_cmap_init(sc); 462 ims332_loadcmap(&sc->sc_cmap); 463 sc->sc_blanked = 0; 464 xcfb_screenblank(sc); 465 } 466 return (0); 467 } 468 return (EPASSTHROUGH); 469} 470 471static paddr_t 472xcfbmmap(void *v, void *vs, off_t offset, int prot) 473{ 474 475 if (offset >= XCFB_FB_SIZE || offset < 0) 476 return (-1); 477 return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset)); 478} 479 480static int 481xcfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 482 int *curxp, int *curyp, long *attrp) 483{ 484 struct xcfb_softc *sc = v; 485 struct rasops_info *ri = sc->sc_ri; 486 long defattr; 487 488 if (sc->nscreens > 0) 489 return (ENOMEM); 490 491 *cookiep = ri; /* one and only for now */ 492 *curxp = 0; 493 *curyp = 0; 494 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 495 *attrp = defattr; 496 sc->nscreens++; 497 return (0); 498} 499 500static void 501xcfb_free_screen(void *v, void *cookie) 502{ 503 struct xcfb_softc *sc = v; 504 505 if (sc->sc_ri == &xcfb_console_ri) 506 panic("xcfb_free_screen: console"); 507 508 sc->nscreens--; 509} 510 511static int 512xcfb_show_screen(void *v, void *cookie, int waitok, 513 void (*cb)(void *, int, int), void *cbarg) 514{ 515 516 return (0); 517} 518 519static int 520xcfbintr(void *v) 521{ 522 struct xcfb_softc *sc = v; 523 u_int32_t *intr, i; 524 525 intr = (u_int32_t *)((char *)sc->sc_ri->ri_hw + IOASIC_INTR); 526 i = *intr; 527 i &= ~XINE_INTR_VINT; 528 *intr = i; 529 return (1); 530} 531 532static void 533xcfb_screenblank(struct xcfb_softc *sc) 534{ 535 if (sc->sc_blanked) 536 sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK; 537 else 538 sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK; 539 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr); 540} 541 542static int 543get_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p) 544{ 545 u_int index = p->index, count = p->count; 546 int error; 547 548 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 549 return (EINVAL); 550 551 error = copyout(&sc->sc_cmap.r[index], p->red, count); 552 if (error) 553 return error; 554 error = copyout(&sc->sc_cmap.g[index], p->green, count); 555 if (error) 556 return error; 557 error = copyout(&sc->sc_cmap.b[index], p->blue, count); 558 return error; 559} 560 561static int 562set_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p) 563{ 564 struct hwcmap256 cmap; 565 u_int index = p->index, count = p->count; 566 int error; 567 568 if (index >= CMAP_SIZE || count > CMAP_SIZE - index) 569 return (EINVAL); 570 571 error = copyin(p->red, &cmap.r[index], count); 572 if (error) 573 return error; 574 error = copyin(p->green, &cmap.g[index], count); 575 if (error) 576 return error; 577 error = copyin(p->blue, &cmap.b[index], count); 578 if (error) 579 return error; 580 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count); 581 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count); 582 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count); 583 return (0); 584} 585 586static int 587set_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p) 588{ 589#define cc (&sc->sc_cursor) 590 u_int v, index = 0, count = 0, icount = 0; 591 uint8_t r[2], g[2], b[2], image[512], mask[512]; 592 int error; 593 594 v = p->which; 595 if (v & WSDISPLAY_CURSOR_DOCMAP) { 596 index = p->cmap.index; 597 count = p->cmap.count; 598 599 if (index >= 2 || index + count > 2) 600 return (EINVAL); 601 error = copyin(p->cmap.red, &r[index], count); 602 if (error) 603 return error; 604 error = copyin(p->cmap.green, &g[index], count); 605 if (error) 606 return error; 607 error = copyin(p->cmap.blue, &b[index], count); 608 if (error) 609 return error; 610 } 611 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 612 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE) 613 return (EINVAL); 614 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y; 615 error = copyin(p->image, image, icount); 616 if (error) 617 return error; 618 error = copyin(p->mask, mask, icount); 619 if (error) 620 return error; 621 } 622 623 if (v & WSDISPLAY_CURSOR_DOCMAP) { 624 memcpy(&cc->cc_color[index], &r[index], count); 625 memcpy(&cc->cc_color[index + 2], &g[index], count); 626 memcpy(&cc->cc_color[index + 4], &b[index], count); 627 ims332_load_curcmap(sc); 628 } 629 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 630 cc->cc_size = p->size; 631 memset(cc->cc_image, 0, sizeof cc->cc_image); 632 memcpy(cc->cc_image, image, icount); 633 memset(cc->cc_mask, 0, sizeof cc->cc_mask); 634 memcpy(cc->cc_mask, mask, icount); 635 ims332_load_curshape(sc); 636 } 637 if (v & WSDISPLAY_CURSOR_DOCUR) { 638 cc->cc_hot = p->hot; 639 if (p->enable) 640 sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR; 641 else 642 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR; 643 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr); 644 } 645 if (v & WSDISPLAY_CURSOR_DOPOS) { 646 set_curpos(sc, &p->pos); 647 ims332_set_curpos(sc); 648 } 649 650 return (0); 651#undef cc 652} 653 654static int 655get_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p) 656{ 657 return (EPASSTHROUGH); /* XXX */ 658} 659 660static void 661set_curpos(struct xcfb_softc *sc, struct wsdisplay_curpos *curpos) 662{ 663 struct rasops_info *ri = sc->sc_ri; 664 int x = curpos->x, y = curpos->y; 665 666 if (y < 0) 667 y = 0; 668 else if (y > ri->ri_height) 669 y = ri->ri_height; 670 if (x < 0) 671 x = 0; 672 else if (x > ri->ri_width) 673 x = ri->ri_width; 674 sc->sc_cursor.cc_pos.x = x; 675 sc->sc_cursor.cc_pos.y = y; 676} 677 678static void 679ims332_loadcmap(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(struct xcfb_softc *sc) 692{ 693 struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos; 694 u_int32_t pos; 695 int s; 696 697 s = spltty(); 698 pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff); 699 ims332_write_reg(IMS332_REG_CURSOR_LOC, pos); 700 splx(s); 701} 702 703static void 704ims332_load_curcmap(struct xcfb_softc *sc) 705{ 706 u_int8_t *cp = sc->sc_cursor.cc_color; 707 u_int32_t rgb; 708 709 /* cursor background */ 710 rgb = cp[5] << 16 | cp[3] << 8 | cp[1]; 711 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb); 712 713 /* cursor foreground */ 714 rgb = cp[4] << 16 | cp[2] << 8 | cp[0]; 715 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb); 716} 717 718static void 719ims332_load_curshape(struct xcfb_softc *sc) 720{ 721 u_int i, img, msk, bits; 722 u_int8_t u, *ip, *mp; 723 724 ip = (u_int8_t *)sc->sc_cursor.cc_image; 725 mp = (u_int8_t *)sc->sc_cursor.cc_mask; 726 727 i = 0; 728 /* 64 pixel scan line is consisted with 8 halfword cursor ram */ 729 while (i < sc->sc_cursor.cc_size.y * 8) { 730 /* pad right half 32 pixel when smaller than 33 */ 731 if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33) 732 bits = 0; 733 else { 734 img = *ip++; 735 msk = *mp++; 736 img &= msk; /* cookie off image */ 737 u = (msk & 0x0f) << 4 | (img & 0x0f); 738 bits = shuffle[u]; 739 u = (msk & 0xf0) | (img & 0xf0) >> 4; 740 bits = (shuffle[u] << 8) | bits; 741 } 742 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits); 743 i += 1; 744 } 745 /* pad unoccupied scan lines */ 746 while (i < CURSOR_MAX_SIZE * 8) { 747 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0); 748 i += 1; 749 } 750} 751 752static void 753ims332_write_reg(int regno, u_int32_t val) 754{ 755 void *high8 = (void *)(ioasic_base + IMS332_HIGH); 756 void *low16 = (void *)(ioasic_base + IMS332_WLOW + (regno << 4)); 757 758 *(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8; 759 *(volatile u_int16_t *)low16 = val; 760} 761 762#if 0 763static u_int32_t 764ims332_read_reg(int regno) 765{ 766 void *high8 = (void *)(ioasic_base + IMS332_HIGH); 767 void *low16 = (void *)(ioasic_base + IMS332_RLOW) + (regno << 4); 768 u_int v0, v1; 769 770 v1 = *(volatile u_int16_t *)high8; 771 v0 = *(volatile u_int16_t *)low16; 772 return (v1 & 0xff00) << 8 | v0; 773} 774#endif 775