FreeBSD/Linux Kernel Cross Reference
sys/dev/tc/cfb.c
1 /* $NetBSD: cfb.c,v 1.44 2003/12/20 07:10:00 nisimura Exp $ */
2
3 /*
4 * Copyright (c) 1998, 1999 Tohru Nishimura. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Tohru Nishimura
17 * for the NetBSD Project.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: cfb.c,v 1.44 2003/12/20 07:10:00 nisimura Exp $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
41 #include <sys/buf.h>
42 #include <sys/ioctl.h>
43
44 #include <machine/bus.h>
45 #include <machine/intr.h>
46
47 #include <dev/wscons/wsconsio.h>
48 #include <dev/wscons/wsdisplayvar.h>
49
50 #include <dev/rasops/rasops.h>
51 #include <dev/wsfont/wsfont.h>
52
53 #include <dev/tc/tcvar.h>
54 #include <dev/ic/bt459reg.h>
55
56 #include <uvm/uvm_extern.h>
57
58 #if defined(pmax)
59 #define machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
60 #endif
61
62 #if defined(alpha)
63 #define machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
64 #endif
65
66 /*
67 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have
68 * obscure register layout such as 2nd and 3rd Bt459 registers are
69 * adjacent each other in a word, i.e.,
70 * struct bt459triplet {
71 * struct {
72 * u_int8_t u0;
73 * u_int8_t u1;
74 * u_int8_t u2;
75 * unsigned :8;
76 * } bt_lo;
77 * ...
78 * Although CX has single Bt459, 32bit R/W can be done w/o any trouble.
79 * struct bt459reg {
80 * u_int32_t bt_lo;
81 * u_int32_t bt_hi;
82 * u_int32_t bt_reg;
83 * u_int32_t bt_cmap;
84 * };
85 */
86
87 /* Bt459 hardware registers, memory-mapped in 32bit stride */
88 #define bt_lo 0x0
89 #define bt_hi 0x4
90 #define bt_reg 0x8
91 #define bt_cmap 0xc
92
93 #define REGWRITE32(p,i,v) do { \
94 *(volatile u_int32_t *)((p) + (i)) = (v); tc_wmb(); \
95 } while (0)
96 #define VDACSELECT(p,r) do { \
97 REGWRITE32(p, bt_lo, 0xff & (r)); \
98 REGWRITE32(p, bt_hi, 0x0f & ((r)>>8)); \
99 } while (0)
100
101 struct hwcmap256 {
102 #define CMAP_SIZE 256 /* 256 R/G/B entries */
103 u_int8_t r[CMAP_SIZE];
104 u_int8_t g[CMAP_SIZE];
105 u_int8_t b[CMAP_SIZE];
106 };
107
108 struct hwcursor64 {
109 struct wsdisplay_curpos cc_pos;
110 struct wsdisplay_curpos cc_hot;
111 struct wsdisplay_curpos cc_size;
112 struct wsdisplay_curpos cc_magic;
113 #define CURSOR_MAX_SIZE 64
114 u_int8_t cc_color[6];
115 u_int64_t cc_image[CURSOR_MAX_SIZE];
116 u_int64_t cc_mask[CURSOR_MAX_SIZE];
117 };
118
119 struct cfb_softc {
120 struct device sc_dev;
121 vaddr_t sc_vaddr;
122 size_t sc_size;
123 struct rasops_info *sc_ri;
124 struct hwcmap256 sc_cmap; /* software copy of colormap */
125 struct hwcursor64 sc_cursor; /* software copy of cursor */
126 int sc_blanked;
127 int sc_curenb; /* cursor sprite enabled */
128 int sc_changed; /* need update of hardware */
129 #define WSDISPLAY_CMAP_DOLUT 0x20
130 int nscreens;
131 };
132
133 #define CX_MAGIC_X 220
134 #define CX_MAGIC_Y 35
135
136 #define CX_FB_OFFSET 0x000000
137 #define CX_FB_SIZE 0x100000
138 #define CX_BT459_OFFSET 0x200000
139 #define CX_OFFSET_IREQ 0x300000 /* Interrupt req. control */
140
141 static int cfbmatch(struct device *, struct cfdata *, void *);
142 static void cfbattach(struct device *, struct device *, void *);
143
144 CFATTACH_DECL(cfb, sizeof(struct cfb_softc),
145 cfbmatch, cfbattach, NULL, NULL);
146
147 static void cfb_common_init(struct rasops_info *);
148 static struct rasops_info cfb_console_ri;
149 static tc_addr_t cfb_consaddr;
150
151 static struct wsscreen_descr cfb_stdscreen = {
152 "std", 0, 0,
153 0, /* textops */
154 0, 0,
155 WSSCREEN_REVERSE
156 };
157
158 static const struct wsscreen_descr *_cfb_scrlist[] = {
159 &cfb_stdscreen,
160 };
161
162 static const struct wsscreen_list cfb_screenlist = {
163 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
164 };
165
166 static int cfbioctl(void *, u_long, caddr_t, int, struct proc *);
167 static paddr_t cfbmmap(void *, off_t, int);
168
169 static int cfb_alloc_screen(void *, const struct wsscreen_descr *,
170 void **, int *, int *, long *);
171 static void cfb_free_screen(void *, void *);
172 static int cfb_show_screen(void *, void *, int,
173 void (*) (void *, int, int), void *);
174
175 static const struct wsdisplay_accessops cfb_accessops = {
176 cfbioctl,
177 cfbmmap,
178 cfb_alloc_screen,
179 cfb_free_screen,
180 cfb_show_screen,
181 0 /* load_font */
182 };
183
184 int cfb_cnattach(tc_addr_t);
185 static int cfbintr(void *);
186 static void cfbhwinit(caddr_t);
187 static void cfb_cmap_init(struct cfb_softc *);
188
189 static int get_cmap(struct cfb_softc *, struct wsdisplay_cmap *);
190 static int set_cmap(struct cfb_softc *, struct wsdisplay_cmap *);
191 static int set_cursor(struct cfb_softc *, struct wsdisplay_cursor *);
192 static int get_cursor(struct cfb_softc *, struct wsdisplay_cursor *);
193 static void set_curpos(struct cfb_softc *, struct wsdisplay_curpos *);
194
195 /*
196 * Compose 2 bit/pixel cursor image. Bit order will be reversed.
197 * M M M M I I I I M I M I M I M I
198 * [ before ] [ after ]
199 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3
200 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7
201 */
202 static const u_int8_t shuffle[256] = {
203 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
204 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
205 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
206 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
207 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
208 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
209 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
210 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
211 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
212 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
213 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
214 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
215 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
216 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
217 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
218 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
219 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
220 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
221 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
222 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
223 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
224 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
225 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
226 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
227 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
228 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
229 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
230 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
231 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
232 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
233 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
234 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
235 };
236
237 static int
238 cfbmatch(parent, match, aux)
239 struct device *parent;
240 struct cfdata *match;
241 void *aux;
242 {
243 struct tc_attach_args *ta = aux;
244
245 if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
246 return (0);
247
248 return (1);
249 }
250
251 static void
252 cfbattach(parent, self, aux)
253 struct device *parent, *self;
254 void *aux;
255 {
256 struct cfb_softc *sc = (struct cfb_softc *)self;
257 struct tc_attach_args *ta = aux;
258 struct rasops_info *ri;
259 struct wsemuldisplaydev_attach_args waa;
260 int console;
261
262 console = (ta->ta_addr == cfb_consaddr);
263 if (console) {
264 sc->sc_ri = ri = &cfb_console_ri;
265 sc->nscreens = 1;
266 }
267 else {
268 MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
269 M_DEVBUF, M_NOWAIT);
270 if (ri == NULL) {
271 printf(": can't alloc memory\n");
272 return;
273 }
274 memset(ri, 0, sizeof(struct rasops_info));
275
276 ri->ri_hw = (void *)ta->ta_addr;
277 cfb_common_init(ri);
278 sc->sc_ri = ri;
279 }
280 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
281
282 cfb_cmap_init(sc);
283
284 sc->sc_vaddr = ta->ta_addr;
285 sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
286 sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
287 sc->sc_blanked = sc->sc_curenb = 0;
288
289 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
290
291 /* clear any pending interrupts */
292 *(volatile u_int8_t *)((caddr_t)ri->ri_hw + CX_OFFSET_IREQ) = 0;
293
294 waa.console = console;
295 waa.scrdata = &cfb_screenlist;
296 waa.accessops = &cfb_accessops;
297 waa.accesscookie = sc;
298
299 config_found(self, &waa, wsemuldisplaydevprint);
300 }
301
302 static void
303 cfb_cmap_init(sc)
304 struct cfb_softc *sc;
305 {
306 struct hwcmap256 *cm;
307 const u_int8_t *p;
308 int index;
309
310 cm = &sc->sc_cmap;
311 p = rasops_cmap;
312 for (index = 0; index < CMAP_SIZE; index++, p += 3) {
313 cm->r[index] = p[0];
314 cm->g[index] = p[1];
315 cm->b[index] = p[2];
316 }
317 }
318
319 static void
320 cfb_common_init(ri)
321 struct rasops_info *ri;
322 {
323 caddr_t base;
324 int cookie;
325
326 base = (caddr_t)ri->ri_hw;
327
328 /* initialize colormap and cursor hardware */
329 cfbhwinit(base);
330
331 ri->ri_flg = RI_CENTER;
332 ri->ri_depth = 8;
333 ri->ri_width = 1024;
334 ri->ri_height = 864;
335 ri->ri_stride = 1024;
336 ri->ri_bits = base + CX_FB_OFFSET;
337
338 /* clear the screen */
339 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
340
341 wsfont_init();
342 /* prefer 12 pixel wide font */
343 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
344 WSDISPLAY_FONTORDER_L2R);
345 if (cookie <= 0)
346 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
347 WSDISPLAY_FONTORDER_L2R);
348 if (cookie <= 0) {
349 printf("cfb: font table is empty\n");
350 return;
351 }
352
353 if (wsfont_lock(cookie, &ri->ri_font)) {
354 printf("cfb: couldn't lock font\n");
355 return;
356 }
357 ri->ri_wsfcookie = cookie;
358
359 rasops_init(ri, 34, 80);
360
361 /* XXX shouldn't be global */
362 cfb_stdscreen.nrows = ri->ri_rows;
363 cfb_stdscreen.ncols = ri->ri_cols;
364 cfb_stdscreen.textops = &ri->ri_ops;
365 cfb_stdscreen.capabilities = ri->ri_caps;
366 }
367
368 static int
369 cfbioctl(v, cmd, data, flag, p)
370 void *v;
371 u_long cmd;
372 caddr_t data;
373 int flag;
374 struct proc *p;
375 {
376 struct cfb_softc *sc = v;
377 struct rasops_info *ri = sc->sc_ri;
378 int turnoff, s;
379
380 switch (cmd) {
381 case WSDISPLAYIO_GTYPE:
382 *(u_int *)data = WSDISPLAY_TYPE_CFB;
383 return (0);
384
385 case WSDISPLAYIO_GINFO:
386 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
387 wsd_fbip->height = ri->ri_height;
388 wsd_fbip->width = ri->ri_width;
389 wsd_fbip->depth = ri->ri_depth;
390 wsd_fbip->cmsize = CMAP_SIZE;
391 #undef fbt
392 return (0);
393
394 case WSDISPLAYIO_GETCMAP:
395 return get_cmap(sc, (struct wsdisplay_cmap *)data);
396
397 case WSDISPLAYIO_PUTCMAP:
398 return set_cmap(sc, (struct wsdisplay_cmap *)data);
399
400 case WSDISPLAYIO_SVIDEO:
401 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
402 if ((sc->sc_blanked == 0) ^ turnoff) {
403 sc->sc_blanked = turnoff;
404 /* XXX later XXX */
405 }
406 return (0);
407
408 case WSDISPLAYIO_GVIDEO:
409 *(u_int *)data = sc->sc_blanked ?
410 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
411 return (0);
412
413 case WSDISPLAYIO_GCURPOS:
414 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
415 return (0);
416
417 case WSDISPLAYIO_SCURPOS:
418 s = spltty();
419 set_curpos(sc, (struct wsdisplay_curpos *)data);
420 sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
421 splx(s);
422 return (0);
423
424 case WSDISPLAYIO_GCURMAX:
425 ((struct wsdisplay_curpos *)data)->x =
426 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
427 return (0);
428
429 case WSDISPLAYIO_GCURSOR:
430 return get_cursor(sc, (struct wsdisplay_cursor *)data);
431
432 case WSDISPLAYIO_SCURSOR:
433 return set_cursor(sc, (struct wsdisplay_cursor *)data);
434
435 case WSDISPLAYIO_SMODE:
436 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
437 s = spltty();
438 cfb_cmap_init(sc);
439 sc->sc_curenb = 0;
440 sc->sc_blanked = 0;
441 sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
442 WSDISPLAY_CMAP_DOLUT);
443 splx(s);
444 }
445 return (0);
446 }
447 return EPASSTHROUGH;
448 }
449
450 paddr_t
451 cfbmmap(v, offset, prot)
452 void *v;
453 off_t offset;
454 int prot;
455 {
456 struct cfb_softc *sc = v;
457
458 if (offset >= CX_FB_SIZE || offset < 0)
459 return (-1);
460 return machine_btop(sc->sc_vaddr + CX_FB_OFFSET + offset);
461 }
462
463 static int
464 cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
465 void *v;
466 const struct wsscreen_descr *type;
467 void **cookiep;
468 int *curxp, *curyp;
469 long *attrp;
470 {
471 struct cfb_softc *sc = v;
472 struct rasops_info *ri = sc->sc_ri;
473 long defattr;
474
475 if (sc->nscreens > 0)
476 return (ENOMEM);
477
478 *cookiep = ri; /* one and only for now */
479 *curxp = 0;
480 *curyp = 0;
481 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
482 *attrp = defattr;
483 sc->nscreens++;
484 return (0);
485 }
486
487 static void
488 cfb_free_screen(v, cookie)
489 void *v;
490 void *cookie;
491 {
492 struct cfb_softc *sc = v;
493
494 if (sc->sc_ri == &cfb_console_ri)
495 panic("cfb_free_screen: console");
496
497 sc->nscreens--;
498 }
499
500 static int
501 cfb_show_screen(v, cookie, waitok, cb, cbarg)
502 void *v;
503 void *cookie;
504 int waitok;
505 void (*cb)(void *, int, int);
506 void *cbarg;
507 {
508
509 return (0);
510 }
511
512 /* EXPORT */ int
513 cfb_cnattach(addr)
514 tc_addr_t addr;
515 {
516 struct rasops_info *ri;
517 long defattr;
518
519 ri = &cfb_console_ri;
520 ri->ri_hw = (void *)addr;
521 cfb_common_init(ri);
522 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
523 wsdisplay_cnattach(&cfb_stdscreen, ri, 0, 0, defattr);
524 cfb_consaddr = addr;
525 return(0);
526 }
527
528 static int
529 cfbintr(arg)
530 void *arg;
531 {
532 struct cfb_softc *sc = arg;
533 caddr_t base, vdac;
534 int v;
535
536 base = (caddr_t)sc->sc_ri->ri_hw;
537 *(u_int8_t *)(base + CX_OFFSET_IREQ) = 0;
538 if (sc->sc_changed == 0)
539 return (1);
540
541 vdac = base + CX_BT459_OFFSET;
542 v = sc->sc_changed;
543 if (v & WSDISPLAY_CURSOR_DOCUR) {
544 VDACSELECT(vdac, BT459_IREG_CCR);
545 REGWRITE32(vdac, bt_reg, (sc->sc_curenb) ? 0xc0 : 0x00);
546 }
547 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
548 int x, y;
549
550 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
551 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
552
553 x += sc->sc_cursor.cc_magic.x;
554 y += sc->sc_cursor.cc_magic.y;
555
556 VDACSELECT(vdac, BT459_IREG_CURSOR_X_LOW);
557 REGWRITE32(vdac, bt_reg, x);
558 REGWRITE32(vdac, bt_reg, x >> 8);
559 REGWRITE32(vdac, bt_reg, y);
560 REGWRITE32(vdac, bt_reg, y >> 8);
561 }
562 if (v & WSDISPLAY_CURSOR_DOCMAP) {
563 u_int8_t *cp = sc->sc_cursor.cc_color;
564
565 VDACSELECT(vdac, BT459_IREG_CCOLOR_2);
566 REGWRITE32(vdac, bt_reg, cp[1]);
567 REGWRITE32(vdac, bt_reg, cp[3]);
568 REGWRITE32(vdac, bt_reg, cp[5]);
569
570 REGWRITE32(vdac, bt_reg, cp[0]);
571 REGWRITE32(vdac, bt_reg, cp[2]);
572 REGWRITE32(vdac, bt_reg, cp[4]);
573 }
574 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
575 u_int8_t *ip, *mp, img, msk;
576 u_int8_t u;
577 int bcnt;
578
579 ip = (u_int8_t *)sc->sc_cursor.cc_image;
580 mp = (u_int8_t *)sc->sc_cursor.cc_mask;
581
582 bcnt = 0;
583 VDACSELECT(vdac, BT459_IREG_CRAM_BASE+0);
584 /* 64 pixel scan line is consisted with 16 byte cursor ram */
585 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
586 /* pad right half 32 pixel when smaller than 33 */
587 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
588 REGWRITE32(vdac, bt_reg, 0);
589 REGWRITE32(vdac, bt_reg, 0);
590 }
591 else {
592 img = *ip++;
593 msk = *mp++;
594 img &= msk; /* cookie off image */
595 u = (msk & 0x0f) << 4 | (img & 0x0f);
596 REGWRITE32(vdac, bt_reg, shuffle[u]);
597 u = (msk & 0xf0) | (img & 0xf0) >> 4;
598 REGWRITE32(vdac, bt_reg, shuffle[u]);
599 }
600 bcnt += 2;
601 }
602 /* pad unoccupied scan lines */
603 while (bcnt < CURSOR_MAX_SIZE * 16) {
604 REGWRITE32(vdac, bt_reg, 0);
605 REGWRITE32(vdac, bt_reg, 0);
606 bcnt += 2;
607 }
608 }
609 if (v & WSDISPLAY_CMAP_DOLUT) {
610 struct hwcmap256 *cm = &sc->sc_cmap;
611 int index;
612
613 VDACSELECT(vdac, 0);
614 for (index = 0; index < CMAP_SIZE; index++) {
615 REGWRITE32(vdac, bt_cmap, cm->r[index]);
616 REGWRITE32(vdac, bt_cmap, cm->g[index]);
617 REGWRITE32(vdac, bt_cmap, cm->b[index]);
618 }
619 }
620 sc->sc_changed = 0;
621 return (1);
622 }
623
624 static void
625 cfbhwinit(cfbbase)
626 caddr_t cfbbase;
627 {
628 caddr_t vdac = cfbbase + CX_BT459_OFFSET;
629 const u_int8_t *p;
630 int i;
631
632 VDACSELECT(vdac, BT459_IREG_COMMAND_0);
633 REGWRITE32(vdac, bt_reg, 0x40); /* CMD0 */
634 REGWRITE32(vdac, bt_reg, 0x0); /* CMD1 */
635 REGWRITE32(vdac, bt_reg, 0xc0); /* CMD2 */
636 REGWRITE32(vdac, bt_reg, 0xff); /* PRM */
637 REGWRITE32(vdac, bt_reg, 0); /* 205 */
638 REGWRITE32(vdac, bt_reg, 0x0); /* PBM */
639 REGWRITE32(vdac, bt_reg, 0); /* 207 */
640 REGWRITE32(vdac, bt_reg, 0x0); /* ORM */
641 REGWRITE32(vdac, bt_reg, 0x0); /* OBM */
642 REGWRITE32(vdac, bt_reg, 0x0); /* ILV */
643 REGWRITE32(vdac, bt_reg, 0x0); /* TEST */
644
645 VDACSELECT(vdac, BT459_IREG_CCR);
646 REGWRITE32(vdac, bt_reg, 0x0);
647 REGWRITE32(vdac, bt_reg, 0x0);
648 REGWRITE32(vdac, bt_reg, 0x0);
649 REGWRITE32(vdac, bt_reg, 0x0);
650 REGWRITE32(vdac, bt_reg, 0x0);
651 REGWRITE32(vdac, bt_reg, 0x0);
652 REGWRITE32(vdac, bt_reg, 0x0);
653 REGWRITE32(vdac, bt_reg, 0x0);
654 REGWRITE32(vdac, bt_reg, 0x0);
655 REGWRITE32(vdac, bt_reg, 0x0);
656 REGWRITE32(vdac, bt_reg, 0x0);
657 REGWRITE32(vdac, bt_reg, 0x0);
658 REGWRITE32(vdac, bt_reg, 0x0);
659
660 /* build sane colormap */
661 VDACSELECT(vdac, 0);
662 p = rasops_cmap;
663 for (i = 0; i < CMAP_SIZE; i++, p += 3) {
664 REGWRITE32(vdac, bt_cmap, p[0]);
665 REGWRITE32(vdac, bt_cmap, p[1]);
666 REGWRITE32(vdac, bt_cmap, p[2]);
667 }
668
669 /* clear out cursor image */
670 VDACSELECT(vdac, BT459_IREG_CRAM_BASE);
671 for (i = 0; i < 1024; i++)
672 REGWRITE32(vdac, bt_reg, 0xff);
673
674 /*
675 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
676 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for
677 * image color. CCOLOR_1 will be never used.
678 */
679 VDACSELECT(vdac, BT459_IREG_CCOLOR_1);
680 REGWRITE32(vdac, bt_reg, 0xff);
681 REGWRITE32(vdac, bt_reg, 0xff);
682 REGWRITE32(vdac, bt_reg, 0xff);
683
684 REGWRITE32(vdac, bt_reg, 0);
685 REGWRITE32(vdac, bt_reg, 0);
686 REGWRITE32(vdac, bt_reg, 0);
687
688 REGWRITE32(vdac, bt_reg, 0xff);
689 REGWRITE32(vdac, bt_reg, 0xff);
690 REGWRITE32(vdac, bt_reg, 0xff);
691 }
692
693 static int
694 get_cmap(sc, p)
695 struct cfb_softc *sc;
696 struct wsdisplay_cmap *p;
697 {
698 u_int index = p->index, count = p->count;
699 int error;
700
701 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
702 return (EINVAL);
703
704 error = copyout(&sc->sc_cmap.r[index], p->red, count);
705 if (error)
706 return error;
707 error = copyout(&sc->sc_cmap.g[index], p->green, count);
708 if (error)
709 return error;
710 error = copyout(&sc->sc_cmap.b[index], p->blue, count);
711 return error;
712 }
713
714 static int
715 set_cmap(sc, p)
716 struct cfb_softc *sc;
717 struct wsdisplay_cmap *p;
718 {
719 struct hwcmap256 cmap;
720 u_int index = p->index, count = p->count;
721 int error, s;
722
723 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
724 return (EINVAL);
725
726 error = copyin(p->red, &cmap.r[index], count);
727 if (error)
728 return error;
729 error = copyin(p->green, &cmap.g[index], count);
730 if (error)
731 return error;
732 error = copyin(p->blue, &cmap.b[index], count);
733 if (error)
734 return error;
735 s = spltty();
736 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
737 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
738 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
739 sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
740 splx(s);
741 return (0);
742 }
743
744 static int
745 set_cursor(sc, p)
746 struct cfb_softc *sc;
747 struct wsdisplay_cursor *p;
748 {
749 #define cc (&sc->sc_cursor)
750 u_int v, index = 0, count = 0, icount = 0;
751 uint8_t r[2], g[2], b[2], image[512], mask[512];
752 int error, s;
753
754 v = p->which;
755 if (v & WSDISPLAY_CURSOR_DOCMAP) {
756 index = p->cmap.index;
757 count = p->cmap.count;
758 if (index >= 2 || (index + count) > 2)
759 return (EINVAL);
760 error = copyin(p->cmap.red, &r[index], count);
761 if (error)
762 return error;
763 error = copyin(p->cmap.green, &g[index], count);
764 if (error)
765 return error;
766 error = copyin(p->cmap.blue, &b[index], count);
767 if (error)
768 return error;
769 }
770 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
771 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
772 return (EINVAL);
773 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
774 error = copyin(p->image, image, icount);
775 if (error)
776 return error;
777 error = copyin(p->mask, mask, icount);
778 if (error)
779 return error;
780 }
781
782 s = spltty();
783 if (v & WSDISPLAY_CURSOR_DOCUR)
784 sc->sc_curenb = p->enable;
785 if (v & WSDISPLAY_CURSOR_DOPOS)
786 set_curpos(sc, &p->pos);
787 if (v & WSDISPLAY_CURSOR_DOHOT)
788 cc->cc_hot = p->hot;
789 if (v & WSDISPLAY_CURSOR_DOCMAP) {
790 memcpy(&cc->cc_color[index], &r[index], count);
791 memcpy(&cc->cc_color[index + 2], &g[index], count);
792 memcpy(&cc->cc_color[index + 4], &b[index], count);
793 }
794 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
795 cc->cc_size = p->size;
796 memset(cc->cc_image, 0, sizeof cc->cc_image);
797 memcpy(cc->cc_image, image, icount);
798 memset(cc->cc_mask, 0, sizeof cc->cc_mask);
799 memcpy(cc->cc_mask, mask, icount);
800 }
801 sc->sc_changed |= v;
802 splx(s);
803
804 return (0);
805 #undef cc
806 }
807
808 static int
809 get_cursor(sc, p)
810 struct cfb_softc *sc;
811 struct wsdisplay_cursor *p;
812 {
813 return (EPASSTHROUGH); /* XXX */
814 }
815
816 static void
817 set_curpos(sc, curpos)
818 struct cfb_softc *sc;
819 struct wsdisplay_curpos *curpos;
820 {
821 struct rasops_info *ri = sc->sc_ri;
822 int x = curpos->x, y = curpos->y;
823
824 if (y < 0)
825 y = 0;
826 else if (y > ri->ri_height)
827 y = ri->ri_height;
828 if (x < 0)
829 x = 0;
830 else if (x > ri->ri_width)
831 x = ri->ri_width;
832 sc->sc_cursor.cc_pos.x = x;
833 sc->sc_cursor.cc_pos.y = y;
834 }
Cache object: 3ac05abd2543c4dc0eb07db0ee088fe7
|