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