1 1.19 tsutsui /* $NetBSD: pm.c,v 1.19 2023/02/11 18:30:45 tsutsui Exp $ */ 2 1.2 ad 3 1.2 ad /*- 4 1.2 ad * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc. 5 1.2 ad * All rights reserved. 6 1.2 ad * 7 1.2 ad * This code is derived from software contributed to The NetBSD Foundation 8 1.2 ad * by Andrew Doran. 9 1.2 ad * 10 1.2 ad * Redistribution and use in source and binary forms, with or without 11 1.2 ad * modification, are permitted provided that the following conditions 12 1.2 ad * are met: 13 1.2 ad * 1. Redistributions of source code must retain the above copyright 14 1.2 ad * notice, this list of conditions and the following disclaimer. 15 1.2 ad * 2. Redistributions in binary form must reproduce the above copyright 16 1.2 ad * notice, this list of conditions and the following disclaimer in the 17 1.2 ad * documentation and/or other materials provided with the distribution. 18 1.2 ad * 19 1.2 ad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.2 ad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.2 ad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.2 ad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.2 ad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.2 ad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.2 ad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.2 ad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.2 ad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.2 ad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.2 ad * POSSIBILITY OF SUCH DAMAGE. 30 1.2 ad */ 31 1.2 ad 32 1.2 ad #include <sys/cdefs.h> 33 1.19 tsutsui __KERNEL_RCSID(0, "$NetBSD: pm.c,v 1.19 2023/02/11 18:30:45 tsutsui Exp $"); 34 1.2 ad 35 1.2 ad #include <sys/param.h> 36 1.10 matt #include <sys/buf.h> 37 1.10 matt #include <sys/bus.h> 38 1.2 ad #include <sys/device.h> 39 1.2 ad #include <sys/ioctl.h> 40 1.10 matt #include <sys/intr.h> 41 1.10 matt #include <sys/kernel.h> 42 1.10 matt #include <sys/systm.h> 43 1.2 ad 44 1.2 ad #include <dev/wscons/wsconsio.h> 45 1.2 ad #include <dev/wscons/wsdisplayvar.h> 46 1.2 ad #include <dev/rasops/rasops.h> 47 1.2 ad #include <dev/wsfont/wsfont.h> 48 1.2 ad 49 1.19 tsutsui #include <dev/ic/dc503reg.h> 50 1.19 tsutsui 51 1.2 ad #include <pmax/pmax/kn01.h> 52 1.2 ad 53 1.2 ad #include <pmax/ibus/ibusvar.h> 54 1.2 ad #include <pmax/ibus/pmreg.h> 55 1.2 ad 56 1.2 ad #include <uvm/uvm_extern.h> 57 1.2 ad 58 1.2 ad #define CURSOR_MAX_SIZE 16 59 1.2 ad 60 1.2 ad struct hwcmap256 { 61 1.2 ad uint8_t r[256]; 62 1.2 ad uint8_t g[256]; 63 1.2 ad uint8_t b[256]; 64 1.2 ad }; 65 1.2 ad 66 1.2 ad struct hwcursor64 { 67 1.2 ad struct wsdisplay_curpos cc_pos; 68 1.2 ad struct wsdisplay_curpos cc_hot; 69 1.2 ad struct wsdisplay_curpos cc_size; 70 1.2 ad uint8_t cc_color[6]; 71 1.2 ad 72 1.2 ad /* 73 1.2 ad * Max cursor size is 16x16. The X server pads bitmap scanlines to 74 1.2 ad * a word boundary. We take the easy route and waste some space. 75 1.2 ad */ 76 1.2 ad u_short cc_image[32 + 32]; 77 1.2 ad }; 78 1.2 ad 79 1.2 ad struct pm_softc { 80 1.9 tsutsui device_t sc_dev; 81 1.2 ad size_t sc_cmap_size; 82 1.2 ad size_t sc_fb_size; 83 1.2 ad int sc_type; 84 1.2 ad int sc_blanked; 85 1.2 ad int sc_curenb; 86 1.2 ad int sc_changed; 87 1.2 ad int sc_nscreens; 88 1.2 ad struct hwcursor64 sc_cursor; 89 1.2 ad struct hwcmap256 sc_cmap; 90 1.2 ad }; 91 1.2 ad #define WSDISPLAY_CMAP_DOLUT 0x20 92 1.2 ad 93 1.9 tsutsui int pm_match(device_t, cfdata_t, void *); 94 1.9 tsutsui void pm_attach(device_t, device_t, void *); 95 1.14 flxd int pm_check_vfb(void); 96 1.5 christos int pm_ioctl(void *, void *, u_long, void *, int, struct lwp *); 97 1.4 jmmv paddr_t pm_mmap(void *, void *, off_t, int); 98 1.2 ad int pm_alloc_screen(void *, const struct wsscreen_descr *, 99 1.2 ad void **, int *, int *, long *); 100 1.2 ad void pm_free_screen(void *, void *); 101 1.2 ad int pm_show_screen(void *, void *, int, 102 1.2 ad void (*) (void *, int, int), void *); 103 1.2 ad void pm_cursor_off(void); 104 1.2 ad void pm_cursor_on(struct pm_softc *); 105 1.2 ad int pm_cnattach(void); 106 1.2 ad void pm_common_init(void); 107 1.2 ad int pm_flush(struct pm_softc *); 108 1.2 ad int pm_get_cmap(struct pm_softc *, struct wsdisplay_cmap *); 109 1.2 ad int pm_set_cmap(struct pm_softc *, struct wsdisplay_cmap *); 110 1.2 ad int pm_set_cursor(struct pm_softc *, struct wsdisplay_cursor *); 111 1.2 ad int pm_get_cursor(struct pm_softc *, struct wsdisplay_cursor *); 112 1.2 ad void pm_set_curpos(struct pm_softc *, struct wsdisplay_curpos *); 113 1.2 ad void pm_init_cmap(struct pm_softc *); 114 1.2 ad 115 1.9 tsutsui CFATTACH_DECL_NEW(pm, sizeof(struct pm_softc), 116 1.2 ad pm_match, pm_attach, NULL, NULL); 117 1.2 ad 118 1.2 ad struct rasops_info pm_ri; 119 1.2 ad 120 1.2 ad struct wsscreen_descr pm_stdscreen = { 121 1.2 ad "std", 0, 0, 122 1.2 ad 0, /* textops */ 123 1.2 ad 0, 0, 124 1.2 ad WSSCREEN_REVERSE 125 1.2 ad }; 126 1.2 ad 127 1.2 ad const struct wsscreen_descr *_pm_scrlist[] = { 128 1.2 ad &pm_stdscreen, 129 1.2 ad }; 130 1.2 ad 131 1.2 ad const struct wsscreen_list pm_screenlist = { 132 1.2 ad sizeof(_pm_scrlist) / sizeof(struct wsscreen_descr *), _pm_scrlist 133 1.2 ad }; 134 1.2 ad 135 1.2 ad const struct wsdisplay_accessops pm_accessops = { 136 1.2 ad pm_ioctl, 137 1.2 ad pm_mmap, 138 1.2 ad pm_alloc_screen, 139 1.2 ad pm_free_screen, 140 1.2 ad pm_show_screen, 141 1.2 ad 0 /* load_font */ 142 1.2 ad }; 143 1.2 ad 144 1.2 ad u_int pm_creg; 145 1.2 ad 146 1.2 ad int 147 1.9 tsutsui pm_match(device_t parent, cfdata_t cf, void *aux) 148 1.2 ad { 149 1.2 ad struct ibus_attach_args *ia; 150 1.5 christos void *pmaddr; 151 1.2 ad 152 1.2 ad ia = aux; 153 1.5 christos pmaddr = (void *)ia->ia_addr; 154 1.2 ad 155 1.2 ad if (strcmp(ia->ia_name, "pm") != 0) 156 1.2 ad return (0); 157 1.2 ad 158 1.2 ad if (badaddr(pmaddr, 4)) 159 1.2 ad return (0); 160 1.2 ad 161 1.2 ad return (1); 162 1.2 ad } 163 1.2 ad 164 1.2 ad void 165 1.9 tsutsui pm_attach(device_t parent, device_t self, void *aux) 166 1.2 ad { 167 1.2 ad struct pm_softc *sc; 168 1.2 ad struct rasops_info *ri; 169 1.2 ad struct wsemuldisplaydev_attach_args waa; 170 1.2 ad int console; 171 1.2 ad 172 1.9 tsutsui sc = device_private(self); 173 1.9 tsutsui sc->sc_dev = self; 174 1.2 ad ri = &pm_ri; 175 1.2 ad console = (ri->ri_bits != NULL); 176 1.2 ad 177 1.8 tsutsui if (console) { 178 1.2 ad sc->sc_nscreens = 1; 179 1.8 tsutsui ri->ri_flg &= ~RI_NO_AUTO; 180 1.14 flxd } else if (!pm_check_vfb()) { 181 1.14 flxd printf(": VFB01/VFB02 frame buffer option not found\n"); 182 1.14 flxd return; 183 1.8 tsutsui } else 184 1.2 ad pm_common_init(); 185 1.2 ad 186 1.2 ad printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth); 187 1.2 ad 188 1.2 ad pm_init_cmap(sc); 189 1.2 ad 190 1.2 ad sc->sc_blanked = 0; 191 1.2 ad sc->sc_curenb = 0; 192 1.2 ad 193 1.2 ad waa.console = console; 194 1.2 ad waa.scrdata = &pm_screenlist; 195 1.2 ad waa.accessops = &pm_accessops; 196 1.2 ad waa.accesscookie = sc; 197 1.2 ad 198 1.18 thorpej config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE); 199 1.2 ad } 200 1.2 ad 201 1.14 flxd int 202 1.14 flxd pm_check_vfb(void) 203 1.14 flxd { 204 1.14 flxd int *mem; 205 1.14 flxd const int magic = 0xcafebabe; 206 1.14 flxd 207 1.14 flxd mem = (void *)MIPS_PHYS_TO_KSEG1(KN01_PHYS_FBUF_START); 208 1.14 flxd 209 1.14 flxd *mem = magic; 210 1.14 flxd wbflush(); 211 1.14 flxd if (*mem != magic) 212 1.14 flxd return 0; 213 1.14 flxd 214 1.14 flxd *mem = ~magic; 215 1.14 flxd wbflush(); 216 1.14 flxd if (*mem != ~magic) 217 1.14 flxd return 0; 218 1.14 flxd 219 1.14 flxd return 1; 220 1.14 flxd } 221 1.14 flxd 222 1.2 ad void 223 1.2 ad pm_init_cmap(struct pm_softc *sc) 224 1.2 ad { 225 1.2 ad struct hwcmap256 *cm; 226 1.2 ad struct rasops_info *ri; 227 1.2 ad const uint8_t *p; 228 1.2 ad int index; 229 1.2 ad 230 1.2 ad cm = &sc->sc_cmap; 231 1.2 ad ri = &pm_ri; 232 1.2 ad 233 1.2 ad if (ri->ri_depth == 8) { 234 1.2 ad p = rasops_cmap; 235 1.2 ad for (index = 0; index < 256; index++, p += 3) { 236 1.2 ad cm->r[index] = p[0]; 237 1.2 ad cm->g[index] = p[1]; 238 1.2 ad cm->b[index] = p[2]; 239 1.2 ad } 240 1.2 ad 241 1.2 ad sc->sc_type = WSDISPLAY_TYPE_PM_COLOR; 242 1.2 ad sc->sc_cmap_size = 256; 243 1.2 ad sc->sc_fb_size = 0x100000; 244 1.2 ad } else { 245 1.2 ad cm->r[0] = 0x00; 246 1.2 ad cm->g[0] = 0x00; 247 1.2 ad cm->b[0] = 0x00; 248 1.2 ad 249 1.2 ad cm->r[1] = 0x00; 250 1.2 ad cm->g[1] = 0xff; 251 1.2 ad cm->b[1] = 0x00; 252 1.2 ad 253 1.2 ad sc->sc_type = WSDISPLAY_TYPE_PM_MONO; 254 1.2 ad sc->sc_cmap_size = 2; 255 1.2 ad sc->sc_fb_size = 0x40000; 256 1.2 ad } 257 1.2 ad } 258 1.2 ad 259 1.2 ad void 260 1.2 ad pm_common_init(void) 261 1.2 ad { 262 1.2 ad struct rasops_info *ri; 263 1.2 ad int cookie, bior, i; 264 1.19 tsutsui struct dc503reg *pcc; 265 1.2 ad VDACRegs *vdac; 266 1.2 ad uint16_t kn01csr; 267 1.2 ad 268 1.2 ad kn01csr = *(volatile uint16_t *)MIPS_PHYS_TO_KSEG1(KN01_SYS_CSR); 269 1.2 ad pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC); 270 1.2 ad vdac = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_VDAC); 271 1.2 ad ri = &pm_ri; 272 1.2 ad 273 1.2 ad ri->ri_flg = RI_CENTER; 274 1.8 tsutsui if (ri->ri_bits == NULL) 275 1.8 tsutsui ri->ri_flg |= RI_NO_AUTO; 276 1.2 ad ri->ri_depth = ((kn01csr & KN01_CSR_MONO) != 0 ? 1 : 8); 277 1.2 ad ri->ri_width = 1024; 278 1.2 ad ri->ri_height = 864; 279 1.2 ad ri->ri_stride = (ri->ri_depth == 8 ? 1024 : 2048 / 8); 280 1.2 ad ri->ri_bits = (void *)MIPS_PHYS_TO_KSEG1(KN01_PHYS_FBUF_START); 281 1.2 ad 282 1.2 ad /* 283 1.2 ad * Clear the screen. 284 1.2 ad */ 285 1.2 ad memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height); 286 1.2 ad 287 1.2 ad /* 288 1.2 ad * Get a font to use. 289 1.2 ad */ 290 1.2 ad bior = (ri->ri_depth == 8 ? WSDISPLAY_FONTORDER_L2R : 291 1.2 ad WSDISPLAY_FONTORDER_R2L); 292 1.2 ad 293 1.2 ad wsfont_init(); 294 1.2 ad if (ri->ri_depth == 8) 295 1.2 ad cookie = wsfont_find(NULL, 12, 0, 0, bior, 296 1.11 macallan WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 297 1.2 ad else 298 1.2 ad cookie = wsfont_find(NULL, 8, 0, 0, bior, 299 1.11 macallan WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 300 1.2 ad if (cookie <= 0) 301 1.2 ad cookie = wsfont_find(NULL, 0, 0, 0, bior, 302 1.11 macallan WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP); 303 1.2 ad if (cookie <= 0) { 304 1.2 ad printf("pm: font table is empty\n"); 305 1.2 ad return; 306 1.2 ad } 307 1.2 ad 308 1.2 ad if (wsfont_lock(cookie, &ri->ri_font)) { 309 1.2 ad printf("pm: couldn't lock font\n"); 310 1.2 ad return; 311 1.2 ad } 312 1.2 ad ri->ri_wsfcookie = cookie; 313 1.2 ad 314 1.2 ad /* 315 1.2 ad * Set up the raster operations set. 316 1.2 ad */ 317 1.2 ad rasops_init(ri, 1000, 1000); 318 1.2 ad 319 1.2 ad pm_stdscreen.nrows = ri->ri_rows; 320 1.2 ad pm_stdscreen.ncols = ri->ri_cols; 321 1.2 ad pm_stdscreen.textops = &ri->ri_ops; 322 1.2 ad pm_stdscreen.capabilities = ri->ri_caps; 323 1.2 ad 324 1.2 ad /* 325 1.16 msaitoh * Initialize the VDAC. 326 1.2 ad */ 327 1.2 ad *(uint8_t *)MIPS_PHYS_TO_KSEG1(KN01_PHYS_COLMASK_START) = 0xff; 328 1.2 ad wbflush(); 329 1.2 ad 330 1.2 ad vdac->overWA = 0x04; wbflush(); 331 1.2 ad vdac->over = 0x00; wbflush(); 332 1.2 ad vdac->over = 0x00; wbflush(); 333 1.2 ad vdac->over = 0x00; wbflush(); 334 1.2 ad vdac->overWA = 0x08; wbflush(); 335 1.2 ad vdac->over = 0x00; wbflush(); 336 1.2 ad vdac->over = 0x00; wbflush(); 337 1.2 ad vdac->over = 0x7f; wbflush(); 338 1.2 ad vdac->overWA = 0x0c; wbflush(); 339 1.2 ad vdac->over = 0xff; wbflush(); 340 1.2 ad vdac->over = 0xff; wbflush(); 341 1.2 ad vdac->over = 0xff; wbflush(); 342 1.2 ad 343 1.2 ad /* 344 1.2 ad * Set in the initial colormap. 345 1.2 ad */ 346 1.2 ad if (ri->ri_depth == 8) { 347 1.2 ad vdac->mapWA = 0; 348 1.2 ad wbflush(); 349 1.2 ad 350 1.2 ad for (i = 0; i < 256 * 3; i += 3) { 351 1.2 ad vdac->map = rasops_cmap[i]; 352 1.2 ad wbflush(); 353 1.2 ad vdac->map = rasops_cmap[i + 1]; 354 1.2 ad wbflush(); 355 1.2 ad vdac->map = rasops_cmap[i + 2]; 356 1.2 ad wbflush(); 357 1.2 ad } 358 1.2 ad } else { 359 1.2 ad vdac->mapWA = 0; 360 1.2 ad wbflush(); 361 1.2 ad 362 1.2 ad for (i = 0; i < 256; i++) { 363 1.2 ad vdac->map = 0x00; 364 1.2 ad wbflush(); 365 1.2 ad vdac->map = (i < 128 ? 0x00 : 0xff); 366 1.2 ad wbflush(); 367 1.2 ad vdac->map = 0x00; 368 1.2 ad wbflush(); 369 1.2 ad } 370 1.2 ad } 371 1.2 ad 372 1.2 ad /* 373 1.2 ad * Turn off the hardware cursor sprite for text mode. 374 1.2 ad */ 375 1.19 tsutsui pcc->cmdr = PCCCMD_FOPB | PCCCMD_VBHI; 376 1.2 ad wbflush(); 377 1.2 ad pm_creg = 0; 378 1.2 ad pm_cursor_off(); 379 1.2 ad } 380 1.2 ad 381 1.2 ad void 382 1.2 ad pm_cursor_off(void) 383 1.2 ad { 384 1.19 tsutsui struct dc503reg *pcc; 385 1.2 ad 386 1.2 ad pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC); 387 1.19 tsutsui pcc->cmdr = (pm_creg &= ~(PCCCMD_ENPA | PCCCMD_ENPB)); 388 1.2 ad wbflush(); 389 1.2 ad } 390 1.2 ad 391 1.2 ad void 392 1.2 ad pm_cursor_on(struct pm_softc *sc) 393 1.2 ad { 394 1.19 tsutsui struct dc503reg *pcc; 395 1.2 ad 396 1.2 ad if (sc->sc_curenb) { 397 1.2 ad pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC); 398 1.19 tsutsui pcc->cmdr = (pm_creg |= (PCCCMD_ENPA | PCCCMD_ENPB)); 399 1.2 ad wbflush(); 400 1.2 ad } 401 1.2 ad } 402 1.2 ad 403 1.2 ad int 404 1.5 christos pm_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 405 1.2 ad { 406 1.2 ad struct pm_softc *sc; 407 1.2 ad struct rasops_info *ri; 408 1.2 ad int turnoff, rv, i; 409 1.19 tsutsui struct dc503reg *pcc; 410 1.2 ad VDACRegs *vdac; 411 1.2 ad 412 1.2 ad sc = v; 413 1.2 ad ri = &pm_ri; 414 1.2 ad rv = 0; 415 1.2 ad pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC); 416 1.2 ad vdac = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_VDAC); 417 1.2 ad 418 1.2 ad switch (cmd) { 419 1.2 ad case WSDISPLAYIO_GTYPE: 420 1.2 ad *(u_int *)data = sc->sc_type; 421 1.2 ad break; 422 1.2 ad 423 1.2 ad case WSDISPLAYIO_SMODE: 424 1.2 ad if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL) { 425 1.2 ad pm_cursor_off(); 426 1.2 ad pm_init_cmap(sc); 427 1.2 ad memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height); 428 1.2 ad sc->sc_curenb = 0; 429 1.2 ad sc->sc_changed |= WSDISPLAY_CMAP_DOLUT; 430 1.2 ad } 431 1.2 ad break; 432 1.2 ad 433 1.2 ad case WSDISPLAYIO_GINFO: 434 1.2 ad #define wsd_fbip ((struct wsdisplay_fbinfo *)data) 435 1.2 ad wsd_fbip->height = ri->ri_height; 436 1.2 ad wsd_fbip->width = ri->ri_width; 437 1.2 ad wsd_fbip->depth = ri->ri_depth; 438 1.2 ad wsd_fbip->cmsize = sc->sc_cmap_size; 439 1.2 ad #undef fbt 440 1.2 ad break; 441 1.2 ad 442 1.2 ad case WSDISPLAYIO_GETCMAP: 443 1.2 ad rv = pm_get_cmap(sc, (struct wsdisplay_cmap *)data); 444 1.2 ad break; 445 1.2 ad 446 1.2 ad case WSDISPLAYIO_PUTCMAP: 447 1.2 ad rv = pm_set_cmap(sc, (struct wsdisplay_cmap *)data); 448 1.2 ad break; 449 1.2 ad 450 1.2 ad case WSDISPLAYIO_SVIDEO: 451 1.2 ad turnoff = (*(int *)data == WSDISPLAYIO_VIDEO_OFF); 452 1.2 ad if ((sc->sc_blanked == 0) ^ turnoff) { 453 1.2 ad sc->sc_blanked = turnoff; 454 1.2 ad if (turnoff == 0) { 455 1.2 ad pcc->cmdr = 456 1.19 tsutsui (pm_creg &= ~(PCCCMD_FOPA | PCCCMD_FOPB)); 457 1.2 ad wbflush(); 458 1.2 ad pm_cursor_on(sc); 459 1.2 ad sc->sc_changed |= WSDISPLAY_CURSOR_DOCMAP; 460 1.2 ad } else { 461 1.2 ad pm_cursor_off(); 462 1.2 ad pcc->cmdr = 463 1.19 tsutsui (pm_creg |= (PCCCMD_FOPA | PCCCMD_FOPB)); 464 1.2 ad wbflush(); 465 1.2 ad vdac->overWA = 0x0c; 466 1.2 ad wbflush(); 467 1.2 ad for (i = 0; i < 3; i++) { 468 1.2 ad vdac->over = 0; 469 1.2 ad wbflush(); 470 1.2 ad } 471 1.2 ad } 472 1.2 ad } 473 1.2 ad break; 474 1.2 ad 475 1.2 ad case WSDISPLAYIO_GVIDEO: 476 1.2 ad *(u_int *)data = (sc->sc_blanked ? 477 1.2 ad WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON); 478 1.2 ad break; 479 1.2 ad 480 1.2 ad case WSDISPLAYIO_GCURPOS: 481 1.2 ad *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos; 482 1.2 ad break; 483 1.2 ad 484 1.2 ad case WSDISPLAYIO_SCURPOS: 485 1.2 ad pm_set_curpos(sc, (struct wsdisplay_curpos *)data); 486 1.2 ad sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS; 487 1.2 ad break; 488 1.2 ad 489 1.2 ad case WSDISPLAYIO_GCURMAX: 490 1.2 ad ((struct wsdisplay_curpos *)data)->x = 491 1.2 ad ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE; 492 1.2 ad break; 493 1.2 ad 494 1.2 ad case WSDISPLAYIO_GCURSOR: 495 1.2 ad rv = pm_get_cursor(sc, (struct wsdisplay_cursor *)data); 496 1.2 ad break; 497 1.2 ad 498 1.2 ad case WSDISPLAYIO_SCURSOR: 499 1.2 ad rv = pm_set_cursor(sc, (struct wsdisplay_cursor *)data); 500 1.2 ad break; 501 1.2 ad 502 1.2 ad default: 503 1.2 ad rv = ENOTTY; 504 1.2 ad break; 505 1.2 ad } 506 1.2 ad 507 1.2 ad pm_flush(sc); 508 1.2 ad return (rv); 509 1.2 ad } 510 1.2 ad 511 1.2 ad paddr_t 512 1.4 jmmv pm_mmap(void *v, void *vs, off_t offset, int prot) 513 1.2 ad { 514 1.2 ad struct pm_softc *sc; 515 1.2 ad 516 1.2 ad sc = v; 517 1.2 ad 518 1.2 ad if (offset >= sc->sc_fb_size || offset < 0) 519 1.2 ad return (-1); 520 1.2 ad 521 1.2 ad return (mips_btop(KN01_PHYS_FBUF_START + offset)); 522 1.2 ad } 523 1.2 ad 524 1.2 ad int 525 1.2 ad pm_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep, 526 1.2 ad int *curxp, int *curyp, long *attrp) 527 1.2 ad { 528 1.2 ad struct pm_softc *sc; 529 1.2 ad struct rasops_info *ri; 530 1.2 ad long defattr; 531 1.2 ad 532 1.2 ad sc = v; 533 1.2 ad ri = &pm_ri; 534 1.2 ad 535 1.2 ad if (sc->sc_nscreens > 0) 536 1.2 ad return (ENOMEM); 537 1.2 ad 538 1.2 ad *cookiep = ri; /* one and only for now */ 539 1.2 ad *curxp = 0; 540 1.2 ad *curyp = 0; 541 1.2 ad (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 542 1.2 ad *attrp = defattr; 543 1.2 ad sc->sc_nscreens++; 544 1.2 ad return (0); 545 1.2 ad } 546 1.2 ad 547 1.2 ad void 548 1.2 ad pm_free_screen(void *v, void *cookie) 549 1.2 ad { 550 1.2 ad 551 1.2 ad panic("pm_free_screen: console"); 552 1.2 ad } 553 1.2 ad 554 1.2 ad int 555 1.2 ad pm_show_screen(void *v, void *cookie, int waitok, 556 1.2 ad void (*cb)(void *, int, int), void *cbarg) 557 1.2 ad { 558 1.2 ad 559 1.2 ad return (0); 560 1.2 ad } 561 1.2 ad 562 1.2 ad /* EXPORT */ int 563 1.2 ad pm_cnattach(void) 564 1.2 ad { 565 1.2 ad struct rasops_info *ri; 566 1.2 ad long defattr; 567 1.2 ad 568 1.2 ad ri = &pm_ri; 569 1.2 ad 570 1.2 ad pm_common_init(); 571 1.2 ad (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 572 1.2 ad wsdisplay_cnattach(&pm_stdscreen, ri, 0, 0, defattr); 573 1.2 ad return (1); 574 1.2 ad } 575 1.2 ad 576 1.2 ad int 577 1.2 ad pm_flush(struct pm_softc *sc) 578 1.2 ad { 579 1.2 ad VDACRegs *vdac; 580 1.19 tsutsui struct dc503reg *pcc; 581 1.2 ad uint8_t *cp; 582 1.2 ad int v, i, x, y; 583 1.2 ad u_short *p, *pe; 584 1.2 ad struct hwcmap256 *cm; 585 1.2 ad 586 1.2 ad if (sc->sc_changed == 0) 587 1.2 ad return (1); 588 1.2 ad 589 1.2 ad vdac = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_VDAC); 590 1.2 ad pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC); 591 1.2 ad v = sc->sc_changed; 592 1.2 ad 593 1.2 ad if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) { 594 1.2 ad if (sc->sc_curenb) 595 1.2 ad pm_cursor_on(sc); 596 1.2 ad else 597 1.2 ad pm_cursor_off(); 598 1.2 ad } 599 1.2 ad 600 1.2 ad if ((v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) != 0) { 601 1.2 ad x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x; 602 1.2 ad y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y; 603 1.2 ad pcc->xpos = x + PCC_X_OFFSET; 604 1.2 ad pcc->ypos = y + PCC_Y_OFFSET; 605 1.2 ad wbflush(); 606 1.2 ad } 607 1.2 ad if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) { 608 1.2 ad cp = sc->sc_cursor.cc_color; 609 1.2 ad 610 1.2 ad vdac->overWA = 0x04; 611 1.2 ad wbflush(); 612 1.2 ad for (i = 1; i < 6; i += 2) { 613 1.2 ad vdac->over = cp[i]; 614 1.2 ad wbflush(); 615 1.2 ad } 616 1.2 ad 617 1.2 ad vdac->overWA = 0x08; 618 1.2 ad wbflush(); 619 1.2 ad vdac->over = 0x00; 620 1.2 ad wbflush(); 621 1.2 ad vdac->over = 0x00; 622 1.2 ad wbflush(); 623 1.2 ad vdac->over = 0x7f; 624 1.2 ad wbflush(); 625 1.2 ad 626 1.2 ad vdac->overWA = 0x0c; 627 1.2 ad wbflush(); 628 1.2 ad for (i = 0; i < 6; i += 2) { 629 1.2 ad vdac->over = cp[i]; 630 1.2 ad wbflush(); 631 1.2 ad } 632 1.2 ad } 633 1.2 ad if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) { 634 1.19 tsutsui pcc->cmdr = (pm_creg | PCCCMD_LODSA); 635 1.2 ad wbflush(); 636 1.2 ad 637 1.2 ad p = sc->sc_cursor.cc_image; 638 1.2 ad x = 0xffff >> (16 - sc->sc_cursor.cc_size.x); 639 1.2 ad for (pe = p + 64; p < pe; p += 2) { 640 1.19 tsutsui pcc->load = *p & x; 641 1.2 ad wbflush(); 642 1.2 ad } 643 1.2 ad 644 1.19 tsutsui pcc->cmdr = (pm_creg &= ~PCCCMD_LODSA); 645 1.2 ad wbflush(); 646 1.2 ad } 647 1.2 ad 648 1.2 ad if ((v & WSDISPLAY_CMAP_DOLUT) != 0) { 649 1.2 ad cm = &sc->sc_cmap; 650 1.2 ad 651 1.2 ad vdac->mapWA = 0; 652 1.2 ad wbflush(); 653 1.2 ad 654 1.2 ad if (sc->sc_cmap_size == 2) { 655 1.2 ad for (i = 0; i < 128; i++) { 656 1.2 ad vdac->map = 0; 657 1.2 ad wbflush(); 658 1.2 ad vdac->map = cm->g[0]; 659 1.2 ad wbflush(); 660 1.2 ad vdac->map = 0; 661 1.2 ad wbflush(); 662 1.2 ad } 663 1.2 ad for (; i < 256; i++) { 664 1.2 ad vdac->map = 0; 665 1.2 ad wbflush(); 666 1.2 ad vdac->map = cm->g[1]; 667 1.2 ad wbflush(); 668 1.2 ad vdac->map = 0; 669 1.2 ad wbflush(); 670 1.2 ad } 671 1.2 ad } else { 672 1.2 ad for (i = 0; i < sc->sc_cmap_size; i++) { 673 1.2 ad vdac->map = cm->r[i]; 674 1.2 ad wbflush(); 675 1.2 ad vdac->map = cm->g[i]; 676 1.2 ad wbflush(); 677 1.2 ad vdac->map = cm->b[i]; 678 1.2 ad wbflush(); 679 1.2 ad } 680 1.2 ad } 681 1.2 ad } 682 1.2 ad 683 1.2 ad sc->sc_changed = 0; 684 1.2 ad return (1); 685 1.2 ad } 686 1.2 ad 687 1.2 ad int 688 1.2 ad pm_get_cmap(struct pm_softc *sc, struct wsdisplay_cmap *p) 689 1.2 ad { 690 1.2 ad u_int index, count; 691 1.2 ad int rv; 692 1.2 ad 693 1.2 ad index = p->index; 694 1.2 ad count = p->count; 695 1.2 ad 696 1.13 spz if (index >= sc->sc_cmap_size || count > sc->sc_cmap_size - index) 697 1.2 ad return (EINVAL); 698 1.2 ad 699 1.2 ad if ((rv = copyout(&sc->sc_cmap.r[index], p->red, count)) != 0) 700 1.2 ad return (rv); 701 1.2 ad if ((rv = copyout(&sc->sc_cmap.g[index], p->green, count)) != 0) 702 1.2 ad return (rv); 703 1.2 ad return (copyout(&sc->sc_cmap.b[index], p->blue, count)); 704 1.2 ad } 705 1.2 ad 706 1.2 ad int 707 1.2 ad pm_set_cmap(struct pm_softc *sc, struct wsdisplay_cmap *p) 708 1.2 ad { 709 1.2 ad u_int index, count; 710 1.2 ad int rv; 711 1.2 ad 712 1.2 ad index = p->index; 713 1.2 ad count = p->count; 714 1.2 ad 715 1.13 spz if (index >= sc->sc_cmap_size || count > sc->sc_cmap_size - index) 716 1.2 ad return (EINVAL); 717 1.2 ad 718 1.2 ad if ((rv = copyin(p->red, &sc->sc_cmap.r[index], count)) != 0) 719 1.2 ad return (rv); 720 1.2 ad if ((rv = copyin(p->green, &sc->sc_cmap.g[index], count)) != 0) 721 1.2 ad return (rv); 722 1.2 ad if ((rv = copyin(p->blue, &sc->sc_cmap.b[index], count)) != 0) 723 1.2 ad return (rv); 724 1.2 ad sc->sc_changed |= WSDISPLAY_CMAP_DOLUT; 725 1.2 ad return (0); 726 1.2 ad } 727 1.2 ad 728 1.2 ad int 729 1.2 ad pm_set_cursor(struct pm_softc *sc, struct wsdisplay_cursor *p) 730 1.2 ad { 731 1.2 ad u_int v, index, count; 732 1.2 ad struct hwcursor64 *cc; 733 1.2 ad int rv; 734 1.2 ad 735 1.2 ad v = p->which; 736 1.2 ad cc = &sc->sc_cursor; 737 1.2 ad 738 1.2 ad if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) 739 1.2 ad sc->sc_curenb = p->enable; 740 1.2 ad if ((v & WSDISPLAY_CURSOR_DOPOS) != 0) 741 1.2 ad pm_set_curpos(sc, &p->pos); 742 1.2 ad if ((v & WSDISPLAY_CURSOR_DOHOT) != 0) 743 1.2 ad cc->cc_hot = p->hot; 744 1.2 ad if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) { 745 1.2 ad index = p->cmap.index; 746 1.2 ad count = p->cmap.count; 747 1.15 riastrad if (index >= 2 || count > 2 - index) 748 1.2 ad return (EINVAL); 749 1.2 ad 750 1.2 ad rv = copyin(p->cmap.red, &cc->cc_color[index], count); 751 1.2 ad if (rv != 0) 752 1.2 ad return (rv); 753 1.2 ad rv = copyin(p->cmap.green, &cc->cc_color[index + 2], count); 754 1.2 ad if (rv != 0) 755 1.2 ad return (rv); 756 1.2 ad rv = copyin(p->cmap.blue, &cc->cc_color[index + 4], count); 757 1.2 ad if (rv != 0) 758 1.2 ad return (rv); 759 1.2 ad } 760 1.2 ad if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) { 761 1.2 ad if (p->size.x > CURSOR_MAX_SIZE || 762 1.2 ad p->size.y > CURSOR_MAX_SIZE) 763 1.2 ad return (EINVAL); 764 1.2 ad 765 1.2 ad cc->cc_size = p->size; 766 1.2 ad memset(cc->cc_image, 0, sizeof(cc->cc_image)); 767 1.2 ad rv = copyin(p->image, cc->cc_image, p->size.y * 4); 768 1.2 ad if (rv != 0) 769 1.2 ad return (rv); 770 1.2 ad rv = copyin(p->mask, cc->cc_image+32, p->size.y * 4); 771 1.2 ad if (rv != 0) 772 1.2 ad return (rv); 773 1.2 ad } 774 1.2 ad 775 1.2 ad sc->sc_changed |= v; 776 1.2 ad return (0); 777 1.2 ad } 778 1.2 ad 779 1.2 ad int 780 1.2 ad pm_get_cursor(struct pm_softc *sc, struct wsdisplay_cursor *p) 781 1.2 ad { 782 1.2 ad 783 1.2 ad return (ENOTTY); /* XXX */ 784 1.2 ad } 785 1.2 ad 786 1.2 ad void 787 1.2 ad pm_set_curpos(struct pm_softc *sc, struct wsdisplay_curpos *curpos) 788 1.2 ad { 789 1.2 ad struct rasops_info *ri; 790 1.2 ad int x, y; 791 1.2 ad 792 1.2 ad ri = &pm_ri; 793 1.2 ad x = curpos->x; 794 1.2 ad y = curpos->y; 795 1.2 ad 796 1.2 ad if (y < 0) 797 1.2 ad y = 0; 798 1.2 ad else if (y > ri->ri_height) 799 1.2 ad y = ri->ri_height; 800 1.2 ad if (x < 0) 801 1.2 ad x = 0; 802 1.2 ad else if (x > ri->ri_width) 803 1.2 ad x = ri->ri_width; 804 1.2 ad sc->sc_cursor.cc_pos.x = x; 805 1.2 ad sc->sc_cursor.cc_pos.y = y; 806 1.2 ad } 807