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 *
bt485_funcs(void)139 bt485_funcs(void)
140 {
141 return &bt485_funcsstruct;
142 }
143
144 struct ramdac_cookie *
bt485_register(v,sched_update,wr,rd)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
bt485_cninit(v,sched_update,wr,rd)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
bt485_init(rc)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
bt485_set_cmap(rc,cmapp)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
bt485_get_cmap(rc,cmapp)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
bt485_set_cursor(rc,cursorp)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
bt485_get_cursor(rc,cursorp)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
bt485_set_curpos(rc,curposp)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
bt485_get_curpos(rc,curposp)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
bt485_get_curmax(rc,curposp)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
bt485_wr_i(data,ireg,val)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
bt485_rd_i(data,ireg)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
bt485_update(vp)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
bt485_update_curpos(data)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