1 /* $OpenBSD: bt485.c,v 1.15 2024/09/01 03:08:56 jsg Exp $ */ 2 /* $NetBSD: bt485.c,v 1.2 2000/04/02 18:55:01 nathanw Exp $ */ 3 4 /* 5 * Copyright (c) 1995, 1996 Carnegie-Mellon University. 6 * All rights reserved. 7 * 8 * Author: Chris G. Demetriou 9 * 10 * Permission to use, copy, modify and distribute this software and 11 * its documentation is hereby granted, provided that both the copyright 12 * notice and this permission notice appear in all copies of the 13 * software, derivative works or modified versions, and any portions 14 * thereof, and that both notices appear in supporting documentation. 15 * 16 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 17 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 18 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 19 * 20 * Carnegie Mellon requests users of this software to return to 21 * 22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 23 * School of Computer Science 24 * Carnegie Mellon University 25 * Pittsburgh PA 15213-3890 26 * 27 * any improvements or extensions that they make and grant Carnegie the 28 * rights to redistribute these changes. 29 */ 30 31 /* This code was derived from and originally located in sys/dev/pci/ 32 * NetBSD: tga_bt485.c,v 1.4 1999/03/24 05:51:21 mrg Exp 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/device.h> 38 #include <sys/buf.h> 39 #include <sys/kernel.h> 40 #include <sys/malloc.h> 41 42 #include <dev/pci/pcivar.h> 43 #include <dev/ic/bt485reg.h> 44 #include <dev/ic/bt485var.h> 45 #include <dev/ic/ramdac.h> 46 47 #include <dev/wscons/wsconsio.h> 48 #include <dev/wscons/wsdisplayvar.h> 49 #include <dev/rasops/rasops.h> 50 51 /* 52 * Functions exported via the RAMDAC configuration table. 53 */ 54 void bt485_init(struct ramdac_cookie *); 55 int bt485_set_cmap(struct ramdac_cookie *, 56 struct wsdisplay_cmap *); 57 int bt485_get_cmap(struct ramdac_cookie *, 58 struct wsdisplay_cmap *); 59 int bt485_set_cursor(struct ramdac_cookie *, 60 struct wsdisplay_cursor *); 61 int bt485_get_cursor(struct ramdac_cookie *, 62 struct wsdisplay_cursor *); 63 int bt485_set_curpos(struct ramdac_cookie *, 64 struct wsdisplay_curpos *); 65 int bt485_get_curpos(struct ramdac_cookie *, 66 struct wsdisplay_curpos *); 67 int bt485_get_curmax(struct ramdac_cookie *, 68 struct wsdisplay_curpos *); 69 70 /* XXX const */ 71 struct ramdac_funcs bt485_funcsstruct = { 72 "Bt485", 73 bt485_register, 74 bt485_init, 75 bt485_set_cmap, 76 bt485_get_cmap, 77 bt485_set_cursor, 78 bt485_get_cursor, 79 bt485_set_curpos, 80 bt485_get_curpos, 81 bt485_get_curmax, 82 NULL, /* check_curcmap; not needed */ 83 NULL, /* set_curcmap; not needed */ 84 NULL, /* get_curcmap; not needed */ 85 NULL, /* no dot clock to set */ 86 }; 87 88 /* 89 * Private data. 90 */ 91 struct bt485data { 92 void *cookie; /* This is what is passed 93 * around, and is probably 94 * struct tga_devconfig * 95 */ 96 97 int (*ramdac_sched_update)(void *, void (*)(void *)); 98 void (*ramdac_wr)(void *, u_int, u_int8_t); 99 u_int8_t (*ramdac_rd)(void *, u_int); 100 101 int changed; /* what changed; see below */ 102 int curenb; /* cursor enabled */ 103 struct wsdisplay_curpos curpos; /* current cursor position */ 104 struct wsdisplay_curpos curhot; /* cursor hotspot */ 105 char curcmap_r[2]; /* cursor colormap */ 106 char curcmap_g[2]; 107 char curcmap_b[2]; 108 struct wsdisplay_curpos cursize; /* current cursor size */ 109 char curimage[512]; /* cursor image data */ 110 char curmask[512]; /* cursor mask data */ 111 char cmap_r[256]; /* colormap */ 112 char cmap_g[256]; 113 char cmap_b[256]; 114 }; 115 116 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */ 117 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */ 118 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */ 119 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */ 120 #define DATA_ALL_CHANGED 0x0f 121 122 #define CURSOR_MAX_SIZE 64 123 124 /* 125 * Internal functions. 126 */ 127 inline void bt485_wr_i(struct bt485data *, u_int8_t, u_int8_t); 128 inline u_int8_t bt485_rd_i(struct bt485data *, u_int8_t); 129 void bt485_update(void *); 130 void bt485_update_curpos(struct bt485data *); 131 132 /*****************************************************************************/ 133 134 /* 135 * Functions exported via the RAMDAC configuration table. 136 */ 137 138 struct ramdac_funcs * 139 bt485_funcs(void) 140 { 141 return &bt485_funcsstruct; 142 } 143 144 struct ramdac_cookie * 145 bt485_register(v, sched_update, wr, rd) 146 void *v; 147 int (*sched_update)(void *, void (*)(void *)); 148 void (*wr)(void *, u_int, u_int8_t); 149 u_int8_t (*rd)(void *, u_int); 150 { 151 struct bt485data *data; 152 /* 153 * XXX -- comment out of date. rcd. 154 * If we should allocate a new private info struct, do so. 155 * Otherwise, use the one we have (if it's there), or 156 * use the temporary one on the stack. 157 */ 158 data = malloc(sizeof *data, M_DEVBUF, M_WAITOK); 159 /* XXX -- if !data */ 160 data->cookie = v; 161 data->ramdac_sched_update = sched_update; 162 data->ramdac_wr = wr; 163 data->ramdac_rd = rd; 164 return (struct ramdac_cookie *)data; 165 } 166 167 /* 168 * This function exists solely to provide a means to init 169 * the RAMDAC without first registering. It is useful for 170 * initializing the console early on. 171 */ 172 void 173 bt485_cninit(v, sched_update, wr, rd) 174 void *v; 175 int (*sched_update)(void *, void (*)(void *)); 176 void (*wr)(void *, u_int, u_int8_t); 177 u_int8_t (*rd)(void *, u_int); 178 { 179 struct bt485data tmp, *data = &tmp; 180 data->cookie = v; 181 data->ramdac_sched_update = sched_update; 182 data->ramdac_wr = wr; 183 data->ramdac_rd = rd; 184 bt485_init((struct ramdac_cookie *)data); 185 } 186 187 void 188 bt485_init(rc) 189 struct ramdac_cookie *rc; 190 { 191 u_int8_t regval; 192 struct bt485data *data = (struct bt485data *)rc; 193 int i; 194 195 /* 196 * Init the BT485 for normal operation. 197 */ 198 199 /* 200 * Allow indirect register access. (Actually, this is 201 * already enabled. In fact, if it is _disabled_, for 202 * some reason the monitor appears to lose sync!!! (?!?!) 203 */ 204 regval = data->ramdac_rd(data->cookie, BT485_REG_COMMAND_0); 205 regval |= 0x80; 206 /* 207 * Set the RAMDAC to 8 bit resolution, rather than 6 bit 208 * resolution. 209 */ 210 regval |= 0x02; 211 data->ramdac_wr(data->cookie, BT485_REG_COMMAND_0, regval); 212 213 /* Set the RAMDAC to 8BPP (no interesting options). */ 214 data->ramdac_wr(data->cookie, BT485_REG_COMMAND_1, 0x40); 215 216 /* Disable the cursor (for now) */ 217 regval = data->ramdac_rd(data->cookie, BT485_REG_COMMAND_2); 218 regval &= ~0x03; 219 regval |= 0x24; 220 data->ramdac_wr(data->cookie, BT485_REG_COMMAND_2, regval); 221 222 /* Use a 64x64x2 cursor */ 223 regval = bt485_rd_i(data, BT485_IREG_COMMAND_3); 224 regval |= 0x04; 225 regval |= 0x08; 226 bt485_wr_i(data, BT485_IREG_COMMAND_3, regval); 227 228 /* Set the Pixel Mask to something useful */ 229 data->ramdac_wr(data->cookie, BT485_REG_PIXMASK, 0xff); 230 231 /* 232 * Initialize the RAMDAC info struct to hold all of our 233 * data, and fill it in. 234 */ 235 data->changed = DATA_ALL_CHANGED; 236 237 data->curenb = 0; /* cursor disabled */ 238 data->curpos.x = data->curpos.y = 0; /* right now at 0,0 */ 239 data->curhot.x = data->curhot.y = 0; /* hot spot at 0,0 */ 240 241 /* initial cursor colormap: 0 is black, 1 is white */ 242 data->curcmap_r[0] = data->curcmap_g[0] = data->curcmap_b[0] = 0; 243 data->curcmap_r[1] = data->curcmap_g[1] = data->curcmap_b[1] = 0xff; 244 245 /* initial cursor data: 64x64 block of white. */ 246 data->cursize.x = data->cursize.y = 64; 247 for (i = 0; i < 512; i++) 248 data->curimage[i] = data->curmask[i] = 0xff; 249 250 /* Initial colormap: 0 is black, everything else is white */ 251 data->cmap_r[0] = data->cmap_g[0] = data->cmap_b[0] = 0; 252 for (i = 0; i < 256; i++) { 253 data->cmap_r[i] = rasops_cmap[3*i + 0]; 254 data->cmap_g[i] = rasops_cmap[3*i + 1]; 255 data->cmap_b[i] = rasops_cmap[3*i + 2]; 256 } 257 258 bt485_update((void *)data); 259 } 260 261 int 262 bt485_set_cmap(rc, cmapp) 263 struct ramdac_cookie *rc; 264 struct wsdisplay_cmap *cmapp; 265 { 266 struct bt485data *data = (struct bt485data *)rc; 267 u_int count, index; 268 int s, error; 269 270 #ifdef DIAGNOSTIC 271 if (rc == NULL) 272 panic("bt485_set_cmap: rc"); 273 if (cmapp == NULL) 274 panic("bt485_set_cmap: cmapp"); 275 #endif 276 index = cmapp->index; 277 count = cmapp->count; 278 279 if (index >= 256 || count > 256 - index) 280 return (EINVAL); 281 282 s = spltty(); 283 284 if ((error = copyin(cmapp->red, &data->cmap_r[index], count)) != 0) { 285 splx(s); 286 return (error); 287 } 288 if ((error = copyin(cmapp->green, &data->cmap_g[index], count)) != 0) { 289 splx(s); 290 return (error); 291 } 292 if ((error = copyin(cmapp->blue, &data->cmap_b[index], count)) != 0) { 293 splx(s); 294 return (error); 295 } 296 297 data->changed |= DATA_CMAP_CHANGED; 298 299 data->ramdac_sched_update(data->cookie, bt485_update); 300 #ifdef __alpha__ 301 alpha_mb(); 302 #endif 303 splx(s); 304 305 return (0); 306 } 307 308 int 309 bt485_get_cmap(rc, cmapp) 310 struct ramdac_cookie *rc; 311 struct wsdisplay_cmap *cmapp; 312 { 313 struct bt485data *data = (struct bt485data *)rc; 314 u_int count, index; 315 int error; 316 317 if (cmapp->index >= 256 || cmapp->count > 256 - cmapp->index) 318 return (EINVAL); 319 320 count = cmapp->count; 321 index = cmapp->index; 322 323 error = copyout(&data->cmap_r[index], cmapp->red, count); 324 if (error) 325 return (error); 326 error = copyout(&data->cmap_g[index], cmapp->green, count); 327 if (error) 328 return (error); 329 error = copyout(&data->cmap_b[index], cmapp->blue, count); 330 return (error); 331 } 332 333 int 334 bt485_set_cursor(rc, cursorp) 335 struct ramdac_cookie *rc; 336 struct wsdisplay_cursor *cursorp; 337 { 338 struct bt485data *data = (struct bt485data *)rc; 339 u_int count, index; 340 int error; 341 int v, s; 342 343 v = cursorp->which; 344 345 /* 346 * For DOCMAP and DOSHAPE, verify that parameters are OK 347 * before we do anything that we can't recover from. 348 */ 349 if (v & WSDISPLAY_CURSOR_DOCMAP) { 350 index = cursorp->cmap.index; 351 count = cursorp->cmap.count; 352 if (index >= 2 || count > 2 - index) 353 return (EINVAL); 354 } 355 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 356 if ((u_int)cursorp->size.x > CURSOR_MAX_SIZE || 357 (u_int)cursorp->size.y > CURSOR_MAX_SIZE) 358 return (EINVAL); 359 } 360 361 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) { 362 if (v & WSDISPLAY_CURSOR_DOPOS) 363 data->curpos = cursorp->pos; 364 if (v & WSDISPLAY_CURSOR_DOCUR) 365 data->curhot = cursorp->hot; 366 bt485_update_curpos(data); 367 } 368 369 s = spltty(); 370 371 /* Parameters are OK; perform the requested operations. */ 372 if (v & WSDISPLAY_CURSOR_DOCUR) { 373 data->curenb = cursorp->enable; 374 data->changed |= DATA_ENB_CHANGED; 375 } 376 if (v & WSDISPLAY_CURSOR_DOCMAP) { 377 index = cursorp->cmap.index; 378 count = cursorp->cmap.count; 379 if ((error = copyin(cursorp->cmap.red, 380 &data->curcmap_r[index], count)) != 0) { 381 splx(s); 382 return (error); 383 } 384 if ((error = copyin(cursorp->cmap.green, 385 &data->curcmap_g[index], count)) != 0) { 386 splx(s); 387 return (error); 388 } 389 if ((error = copyin(cursorp->cmap.blue, 390 &data->curcmap_b[index], count)) != 0) { 391 splx(s); 392 return (error); 393 } 394 data->changed |= DATA_CURCMAP_CHANGED; 395 } 396 if (v & WSDISPLAY_CURSOR_DOSHAPE) { 397 data->cursize = cursorp->size; 398 count = (CURSOR_MAX_SIZE / NBBY) * data->cursize.y; 399 bzero(data->curimage, sizeof data->curimage); 400 bzero(data->curmask, sizeof data->curmask); 401 if ((error = copyin(cursorp->image, data->curimage, 402 count)) != 0) { 403 splx(s); 404 return (error); 405 } 406 if ((error = copyin(cursorp->mask, data->curmask, 407 count)) != 0) { 408 splx(s); 409 return (error); 410 } 411 data->changed |= DATA_CURSHAPE_CHANGED; 412 } 413 414 if (data->changed) 415 data->ramdac_sched_update(data->cookie, bt485_update); 416 splx(s); 417 418 return (0); 419 } 420 421 int 422 bt485_get_cursor(rc, cursorp) 423 struct ramdac_cookie *rc; 424 struct wsdisplay_cursor *cursorp; 425 { 426 struct bt485data *data = (struct bt485data *)rc; 427 int error, count; 428 429 /* we return everything they want */ 430 cursorp->which = WSDISPLAY_CURSOR_DOALL; 431 432 cursorp->enable = data->curenb; /* DOCUR */ 433 cursorp->pos = data->curpos; /* DOPOS */ 434 cursorp->hot = data->curhot; /* DOHOT */ 435 436 cursorp->cmap.index = 0; /* DOCMAP */ 437 cursorp->cmap.count = 2; 438 if (cursorp->cmap.red != NULL) { 439 error = copyout(data->curcmap_r, cursorp->cmap.red, 2); 440 if (error) 441 return (error); 442 } 443 if (cursorp->cmap.green != NULL) { 444 error = copyout(data->curcmap_g, cursorp->cmap.green, 2); 445 if (error) 446 return (error); 447 } 448 if (cursorp->cmap.blue != NULL) { 449 error = copyout(data->curcmap_b, cursorp->cmap.blue, 2); 450 if (error) 451 return (error); 452 } 453 454 cursorp->size = data->cursize; /* DOSHAPE */ 455 if (cursorp->image != NULL) { 456 count = (CURSOR_MAX_SIZE / NBBY) * data->cursize.y; 457 error = copyout(data->curimage, cursorp->image, count); 458 if (error) 459 return (error); 460 error = copyout(data->curmask, cursorp->mask, count); 461 if (error) 462 return (error); 463 } 464 465 return (0); 466 } 467 468 int 469 bt485_set_curpos(rc, curposp) 470 struct ramdac_cookie *rc; 471 struct wsdisplay_curpos *curposp; 472 { 473 struct bt485data *data = (struct bt485data *)rc; 474 475 data->curpos = *curposp; 476 bt485_update_curpos(data); 477 478 return (0); 479 } 480 481 int 482 bt485_get_curpos(rc, curposp) 483 struct ramdac_cookie *rc; 484 struct wsdisplay_curpos *curposp; 485 { 486 struct bt485data *data = (struct bt485data *)rc; 487 488 *curposp = data->curpos; 489 return (0); 490 } 491 492 int 493 bt485_get_curmax(rc, curposp) 494 struct ramdac_cookie *rc; 495 struct wsdisplay_curpos *curposp; 496 { 497 498 curposp->x = curposp->y = CURSOR_MAX_SIZE; 499 return (0); 500 } 501 502 /*****************************************************************************/ 503 504 /* 505 * Internal functions. 506 */ 507 508 inline void 509 bt485_wr_i(data, ireg, val) 510 struct bt485data *data; 511 u_int8_t ireg; 512 u_int8_t val; 513 { 514 data->ramdac_wr(data->cookie, BT485_REG_PCRAM_WRADDR, ireg); 515 data->ramdac_wr(data->cookie, BT485_REG_EXTENDED, val); 516 } 517 518 inline u_int8_t 519 bt485_rd_i(data, ireg) 520 struct bt485data *data; 521 u_int8_t ireg; 522 { 523 data->ramdac_wr(data->cookie, BT485_REG_PCRAM_WRADDR, ireg); 524 return (data->ramdac_rd(data->cookie, BT485_REG_EXTENDED)); 525 } 526 527 void 528 bt485_update(vp) 529 void *vp; 530 { 531 struct bt485data *data = vp; 532 u_int8_t regval; 533 int count, i, v; 534 535 v = data->changed; 536 data->changed = 0; 537 538 if (v & DATA_ENB_CHANGED) { 539 regval = data->ramdac_rd(data->cookie, BT485_REG_COMMAND_2); 540 if (data->curenb) 541 regval |= 0x01; 542 else 543 regval &= ~0x03; 544 data->ramdac_wr(data->cookie, BT485_REG_COMMAND_2, regval); 545 } 546 547 if (v & DATA_CURCMAP_CHANGED) { 548 /* addr[9:0] assumed to be 0 */ 549 /* set addr[7:0] to 1 */ 550 data->ramdac_wr(data->cookie, BT485_REG_COC_WRADDR, 0x01); 551 552 /* spit out the cursor data */ 553 for (i = 0; i < 2; i++) { 554 data->ramdac_wr(data->cookie, BT485_REG_COCDATA, 555 data->curcmap_r[i]); 556 data->ramdac_wr(data->cookie, BT485_REG_COCDATA, 557 data->curcmap_g[i]); 558 data->ramdac_wr(data->cookie, BT485_REG_COCDATA, 559 data->curcmap_b[i]); 560 } 561 } 562 563 if (v & DATA_CURSHAPE_CHANGED) { 564 count = (CURSOR_MAX_SIZE / NBBY) * data->cursize.y; 565 566 /* 567 * Write the cursor image data: 568 * set addr[9:8] to 0, 569 * set addr[7:0] to 0, 570 * spit it all out. 571 */ 572 regval = bt485_rd_i(data, BT485_IREG_COMMAND_3); 573 regval &= ~0x03; 574 bt485_wr_i(data, BT485_IREG_COMMAND_3, regval); 575 data->ramdac_wr(data->cookie, BT485_REG_PCRAM_WRADDR, 0); 576 for (i = 0; i < count; i++) 577 data->ramdac_wr(data->cookie, BT485_REG_CURSOR_RAM, 578 data->curimage[i]); 579 580 /* 581 * Write the cursor mask data: 582 * set addr[9:8] to 2, 583 * set addr[7:0] to 0, 584 * spit it all out. 585 */ 586 regval = bt485_rd_i(data, BT485_IREG_COMMAND_3); 587 regval &= ~0x03; regval |= 0x02; 588 bt485_wr_i(data, BT485_IREG_COMMAND_3, regval); 589 data->ramdac_wr(data->cookie, BT485_REG_PCRAM_WRADDR, 0); 590 for (i = 0; i < count; i++) 591 data->ramdac_wr(data->cookie, BT485_REG_CURSOR_RAM, 592 data->curmask[i]); 593 594 /* set addr[9:0] back to 0 */ 595 regval = bt485_rd_i(data, BT485_IREG_COMMAND_3); 596 regval &= ~0x03; 597 bt485_wr_i(data, BT485_IREG_COMMAND_3, regval); 598 } 599 600 if (v & DATA_CMAP_CHANGED) { 601 /* addr[9:0] assumed to be 0 */ 602 /* set addr[7:0] to 0 */ 603 data->ramdac_wr(data->cookie, BT485_REG_PCRAM_WRADDR, 0x00); 604 605 /* spit out the cursor data */ 606 for (i = 0; i < 256; i++) { 607 data->ramdac_wr(data->cookie, BT485_REG_PALETTE, 608 data->cmap_r[i]); 609 data->ramdac_wr(data->cookie, BT485_REG_PALETTE, 610 data->cmap_g[i]); 611 data->ramdac_wr(data->cookie, BT485_REG_PALETTE, 612 data->cmap_b[i]); 613 } 614 } 615 } 616 617 void 618 bt485_update_curpos(data) 619 struct bt485data *data; 620 { 621 void *cookie = data->cookie; 622 int s, x, y; 623 624 s = spltty(); 625 626 x = data->curpos.x + CURSOR_MAX_SIZE - data->curhot.x; 627 y = data->curpos.y + CURSOR_MAX_SIZE - data->curhot.y; 628 data->ramdac_wr(cookie, BT485_REG_CURSOR_X_LOW, x & 0xff); 629 data->ramdac_wr(cookie, BT485_REG_CURSOR_X_HIGH, (x >> 8) & 0x0f); 630 data->ramdac_wr(cookie, BT485_REG_CURSOR_Y_LOW, y & 0xff); 631 data->ramdac_wr(cookie, BT485_REG_CURSOR_Y_HIGH, (y >> 8) & 0x0f); 632 633 splx(s); 634 } 635