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