cfb.c revision 1.42 1 /* $NetBSD: cfb.c,v 1.42 2003/11/13 03:09:29 chs 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.42 2003/11/13 03:09:29 chs 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 */
88 #define bt_lo 0
89 #define bt_hi 1
90 #define bt_reg 2
91 #define bt_cmap 3
92
93 #define REG(base, index) *((u_int32_t *)(base) + (index))
94 #define SELECT(vdac, regno) do { \
95 REG(vdac, bt_lo) = ((regno) & 0x00ff); \
96 REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8; \
97 tc_wmb(); \
98 } while (0)
99
100 struct hwcmap256 {
101 #define CMAP_SIZE 256 /* 256 R/G/B entries */
102 u_int8_t r[CMAP_SIZE];
103 u_int8_t g[CMAP_SIZE];
104 u_int8_t b[CMAP_SIZE];
105 };
106
107 struct hwcursor64 {
108 struct wsdisplay_curpos cc_pos;
109 struct wsdisplay_curpos cc_hot;
110 struct wsdisplay_curpos cc_size;
111 struct wsdisplay_curpos cc_magic;
112 #define CURSOR_MAX_SIZE 64
113 u_int8_t cc_color[6];
114 u_int64_t cc_image[CURSOR_MAX_SIZE];
115 u_int64_t cc_mask[CURSOR_MAX_SIZE];
116 };
117
118 struct cfb_softc {
119 struct device sc_dev;
120 vaddr_t sc_vaddr;
121 size_t sc_size;
122 struct rasops_info *sc_ri;
123 struct hwcmap256 sc_cmap; /* software copy of colormap */
124 struct hwcursor64 sc_cursor; /* software copy of cursor */
125 int sc_blanked;
126 int sc_curenb; /* cursor sprite enabled */
127 int sc_changed; /* need update of hardware */
128 #define WSDISPLAY_CMAP_DOLUT 0x20
129 int nscreens;
130 };
131
132 #define CX_MAGIC_X 220
133 #define CX_MAGIC_Y 35
134
135 #define CX_FB_OFFSET 0x000000
136 #define CX_FB_SIZE 0x100000
137 #define CX_BT459_OFFSET 0x200000
138 #define CX_OFFSET_IREQ 0x300000 /* Interrupt req. control */
139
140 static int cfbmatch __P((struct device *, struct cfdata *, void *));
141 static void cfbattach __P((struct device *, struct device *, void *));
142
143 CFATTACH_DECL(cfb, sizeof(struct cfb_softc),
144 cfbmatch, cfbattach, NULL, NULL);
145
146 static void cfb_common_init __P((struct rasops_info *));
147 static struct rasops_info cfb_console_ri;
148 static tc_addr_t cfb_consaddr;
149
150 static struct wsscreen_descr cfb_stdscreen = {
151 "std", 0, 0,
152 0, /* textops */
153 0, 0,
154 WSSCREEN_REVERSE
155 };
156
157 static const struct wsscreen_descr *_cfb_scrlist[] = {
158 &cfb_stdscreen,
159 };
160
161 static const struct wsscreen_list cfb_screenlist = {
162 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
163 };
164
165 static int cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
166 static paddr_t cfbmmap __P((void *, off_t, int));
167
168 static int cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
169 void **, int *, int *, long *));
170 static void cfb_free_screen __P((void *, void *));
171 static int cfb_show_screen __P((void *, void *, int,
172 void (*) (void *, int, int), void *));
173
174 static const struct wsdisplay_accessops cfb_accessops = {
175 cfbioctl,
176 cfbmmap,
177 cfb_alloc_screen,
178 cfb_free_screen,
179 cfb_show_screen,
180 0 /* load_font */
181 };
182
183 int cfb_cnattach __P((tc_addr_t));
184 static int cfbintr __P((void *));
185 static void cfbhwinit __P((caddr_t));
186
187 static int get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
188 static int set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
189 static int set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
190 static int get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
191 static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *));
192
193 /*
194 * Compose 2 bit/pixel cursor image. Bit order will be reversed.
195 * M M M M I I I I M I M I M I M I
196 * [ before ] [ after ]
197 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3
198 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7
199 */
200 static const u_int8_t shuffle[256] = {
201 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
202 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
203 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
204 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
205 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
206 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
207 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
208 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
209 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
210 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
211 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
212 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
213 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
214 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
215 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
216 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
217 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
218 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
219 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
220 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
221 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
222 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
223 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
224 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
225 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
226 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
227 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
228 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
229 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
230 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
231 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
232 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
233 };
234
235 static int
236 cfbmatch(parent, match, aux)
237 struct device *parent;
238 struct cfdata *match;
239 void *aux;
240 {
241 struct tc_attach_args *ta = aux;
242
243 if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
244 return (0);
245
246 return (1);
247 }
248
249 static void
250 cfbattach(parent, self, aux)
251 struct device *parent, *self;
252 void *aux;
253 {
254 struct cfb_softc *sc = (struct cfb_softc *)self;
255 struct tc_attach_args *ta = aux;
256 struct rasops_info *ri;
257 struct wsemuldisplaydev_attach_args waa;
258 struct hwcmap256 *cm;
259 const u_int8_t *p;
260 int console, index;
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 cm = &sc->sc_cmap;
283 p = rasops_cmap;
284 for (index = 0; index < CMAP_SIZE; index++, p += 3) {
285 cm->r[index] = p[0];
286 cm->g[index] = p[1];
287 cm->b[index] = p[2];
288 }
289
290 sc->sc_vaddr = ta->ta_addr;
291 sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
292 sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
293 sc->sc_blanked = sc->sc_curenb = 0;
294
295 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
296
297 /* clear any pending interrupts */
298 *(u_int8_t *)((caddr_t)ri->ri_hw + CX_OFFSET_IREQ) = 0;
299
300 waa.console = console;
301 waa.scrdata = &cfb_screenlist;
302 waa.accessops = &cfb_accessops;
303 waa.accesscookie = sc;
304
305 config_found(self, &waa, wsemuldisplaydevprint);
306 }
307
308 static void
309 cfb_common_init(ri)
310 struct rasops_info *ri;
311 {
312 caddr_t base;
313 int cookie;
314
315 base = (caddr_t)ri->ri_hw;
316
317 /* initialize colormap and cursor hardware */
318 cfbhwinit(base);
319
320 ri->ri_flg = RI_CENTER;
321 ri->ri_depth = 8;
322 ri->ri_width = 1024;
323 ri->ri_height = 864;
324 ri->ri_stride = 1024;
325 ri->ri_bits = base + CX_FB_OFFSET;
326
327 /* clear the screen */
328 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
329
330 wsfont_init();
331 /* prefer 12 pixel wide font */
332 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
333 WSDISPLAY_FONTORDER_L2R);
334 if (cookie <= 0)
335 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
336 WSDISPLAY_FONTORDER_L2R);
337 if (cookie <= 0) {
338 printf("cfb: font table is empty\n");
339 return;
340 }
341
342 if (wsfont_lock(cookie, &ri->ri_font)) {
343 printf("cfb: couldn't lock font\n");
344 return;
345 }
346 ri->ri_wsfcookie = cookie;
347
348 rasops_init(ri, 34, 80);
349
350 /* XXX shouldn't be global */
351 cfb_stdscreen.nrows = ri->ri_rows;
352 cfb_stdscreen.ncols = ri->ri_cols;
353 cfb_stdscreen.textops = &ri->ri_ops;
354 cfb_stdscreen.capabilities = ri->ri_caps;
355 }
356
357 static int
358 cfbioctl(v, cmd, data, flag, p)
359 void *v;
360 u_long cmd;
361 caddr_t data;
362 int flag;
363 struct proc *p;
364 {
365 struct cfb_softc *sc = v;
366 struct rasops_info *ri = sc->sc_ri;
367 int turnoff;
368
369 switch (cmd) {
370 case WSDISPLAYIO_GTYPE:
371 *(u_int *)data = WSDISPLAY_TYPE_CFB;
372 return (0);
373
374 case WSDISPLAYIO_GINFO:
375 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
376 wsd_fbip->height = ri->ri_height;
377 wsd_fbip->width = ri->ri_width;
378 wsd_fbip->depth = ri->ri_depth;
379 wsd_fbip->cmsize = CMAP_SIZE;
380 #undef fbt
381 return (0);
382
383 case WSDISPLAYIO_GETCMAP:
384 return get_cmap(sc, (struct wsdisplay_cmap *)data);
385
386 case WSDISPLAYIO_PUTCMAP:
387 return set_cmap(sc, (struct wsdisplay_cmap *)data);
388
389 case WSDISPLAYIO_SVIDEO:
390 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
391 if ((sc->sc_blanked == 0) ^ turnoff) {
392 sc->sc_blanked = turnoff;
393 /* XXX later XXX */
394 }
395 return (0);
396
397 case WSDISPLAYIO_GVIDEO:
398 *(u_int *)data = sc->sc_blanked ?
399 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
400 return (0);
401
402 case WSDISPLAYIO_GCURPOS:
403 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
404 return (0);
405
406 case WSDISPLAYIO_SCURPOS:
407 set_curpos(sc, (struct wsdisplay_curpos *)data);
408 sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
409 return (0);
410
411 case WSDISPLAYIO_GCURMAX:
412 ((struct wsdisplay_curpos *)data)->x =
413 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
414 return (0);
415
416 case WSDISPLAYIO_GCURSOR:
417 return get_cursor(sc, (struct wsdisplay_cursor *)data);
418
419 case WSDISPLAYIO_SCURSOR:
420 return set_cursor(sc, (struct wsdisplay_cursor *)data);
421 }
422 return EPASSTHROUGH;
423 }
424
425 paddr_t
426 cfbmmap(v, offset, prot)
427 void *v;
428 off_t offset;
429 int prot;
430 {
431 struct cfb_softc *sc = v;
432
433 if (offset >= CX_FB_SIZE || offset < 0)
434 return (-1);
435 return machine_btop(sc->sc_vaddr + CX_FB_OFFSET + offset);
436 }
437
438 static int
439 cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
440 void *v;
441 const struct wsscreen_descr *type;
442 void **cookiep;
443 int *curxp, *curyp;
444 long *attrp;
445 {
446 struct cfb_softc *sc = v;
447 struct rasops_info *ri = sc->sc_ri;
448 long defattr;
449
450 if (sc->nscreens > 0)
451 return (ENOMEM);
452
453 *cookiep = ri; /* one and only for now */
454 *curxp = 0;
455 *curyp = 0;
456 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
457 *attrp = defattr;
458 sc->nscreens++;
459 return (0);
460 }
461
462 static void
463 cfb_free_screen(v, cookie)
464 void *v;
465 void *cookie;
466 {
467 struct cfb_softc *sc = v;
468
469 if (sc->sc_ri == &cfb_console_ri)
470 panic("cfb_free_screen: console");
471
472 sc->nscreens--;
473 }
474
475 static int
476 cfb_show_screen(v, cookie, waitok, cb, cbarg)
477 void *v;
478 void *cookie;
479 int waitok;
480 void (*cb) __P((void *, int, int));
481 void *cbarg;
482 {
483
484 return (0);
485 }
486
487 /* EXPORT */ int
488 cfb_cnattach(addr)
489 tc_addr_t addr;
490 {
491 struct rasops_info *ri;
492 long defattr;
493
494 ri = &cfb_console_ri;
495 ri->ri_hw = (void *)addr;
496 cfb_common_init(ri);
497 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
498 wsdisplay_cnattach(&cfb_stdscreen, ri, 0, 0, defattr);
499 cfb_consaddr = addr;
500 return(0);
501 }
502
503 static int
504 cfbintr(arg)
505 void *arg;
506 {
507 struct cfb_softc *sc = arg;
508 caddr_t base, vdac;
509 int v;
510
511 base = (caddr_t)sc->sc_ri->ri_hw;
512 *(u_int8_t *)(base + CX_OFFSET_IREQ) = 0;
513 if (sc->sc_changed == 0)
514 return (1);
515
516 vdac = base + CX_BT459_OFFSET;
517 v = sc->sc_changed;
518 if (v & WSDISPLAY_CURSOR_DOCUR) {
519 SELECT(vdac, BT459_IREG_CCR);
520 REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
521 }
522 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
523 int x, y;
524
525 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
526 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
527
528 x += sc->sc_cursor.cc_magic.x;
529 y += sc->sc_cursor.cc_magic.y;
530
531 SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
532 REG(vdac, bt_reg) = x; tc_wmb();
533 REG(vdac, bt_reg) = x >> 8; tc_wmb();
534 REG(vdac, bt_reg) = y; tc_wmb();
535 REG(vdac, bt_reg) = y >> 8; tc_wmb();
536 }
537 if (v & WSDISPLAY_CURSOR_DOCMAP) {
538 u_int8_t *cp = sc->sc_cursor.cc_color;
539
540 SELECT(vdac, BT459_IREG_CCOLOR_2);
541 REG(vdac, bt_reg) = cp[1]; tc_wmb();
542 REG(vdac, bt_reg) = cp[3]; tc_wmb();
543 REG(vdac, bt_reg) = cp[5]; tc_wmb();
544
545 REG(vdac, bt_reg) = cp[0]; tc_wmb();
546 REG(vdac, bt_reg) = cp[2]; tc_wmb();
547 REG(vdac, bt_reg) = cp[4]; tc_wmb();
548 }
549 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
550 u_int8_t *ip, *mp, img, msk;
551 u_int8_t u;
552 int bcnt;
553
554 ip = (u_int8_t *)sc->sc_cursor.cc_image;
555 mp = (u_int8_t *)sc->sc_cursor.cc_mask;
556
557 bcnt = 0;
558 SELECT(vdac, BT459_IREG_CRAM_BASE+0);
559 /* 64 pixel scan line is consisted with 16 byte cursor ram */
560 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
561 /* pad right half 32 pixel when smaller than 33 */
562 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
563 REG(vdac, bt_reg) = 0; tc_wmb();
564 REG(vdac, bt_reg) = 0; tc_wmb();
565 }
566 else {
567 img = *ip++;
568 msk = *mp++;
569 img &= msk; /* cookie off image */
570 u = (msk & 0x0f) << 4 | (img & 0x0f);
571 REG(vdac, bt_reg) = shuffle[u]; tc_wmb();
572 u = (msk & 0xf0) | (img & 0xf0) >> 4;
573 REG(vdac, bt_reg) = shuffle[u]; tc_wmb();
574 }
575 bcnt += 2;
576 }
577 /* pad unoccupied scan lines */
578 while (bcnt < CURSOR_MAX_SIZE * 16) {
579 REG(vdac, bt_reg) = 0; tc_wmb();
580 REG(vdac, bt_reg) = 0; tc_wmb();
581 bcnt += 2;
582 }
583 }
584 if (v & WSDISPLAY_CMAP_DOLUT) {
585 struct hwcmap256 *cm = &sc->sc_cmap;
586 int index;
587
588 SELECT(vdac, 0);
589 for (index = 0; index < CMAP_SIZE; index++) {
590 REG(vdac, bt_cmap) = cm->r[index]; tc_wmb();
591 REG(vdac, bt_cmap) = cm->g[index]; tc_wmb();
592 REG(vdac, bt_cmap) = cm->b[index]; tc_wmb();
593 }
594 }
595 sc->sc_changed = 0;
596 return (1);
597 }
598
599 static void
600 cfbhwinit(cfbbase)
601 caddr_t cfbbase;
602 {
603 caddr_t vdac = cfbbase + CX_BT459_OFFSET;
604 const u_int8_t *p;
605 int i;
606
607 SELECT(vdac, BT459_IREG_COMMAND_0);
608 REG(vdac, bt_reg) = 0x40; /* CMD0 */ tc_wmb();
609 REG(vdac, bt_reg) = 0x0; /* CMD1 */ tc_wmb();
610 REG(vdac, bt_reg) = 0xc0; /* CMD2 */ tc_wmb();
611 REG(vdac, bt_reg) = 0xff; /* PRM */ tc_wmb();
612 REG(vdac, bt_reg) = 0; /* 205 */ tc_wmb();
613 REG(vdac, bt_reg) = 0x0; /* PBM */ tc_wmb();
614 REG(vdac, bt_reg) = 0; /* 207 */ tc_wmb();
615 REG(vdac, bt_reg) = 0x0; /* ORM */ tc_wmb();
616 REG(vdac, bt_reg) = 0x0; /* OBM */ tc_wmb();
617 REG(vdac, bt_reg) = 0x0; /* ILV */ tc_wmb();
618 REG(vdac, bt_reg) = 0x0; /* TEST */ tc_wmb();
619
620 SELECT(vdac, BT459_IREG_CCR);
621 REG(vdac, bt_reg) = 0x0; tc_wmb();
622 REG(vdac, bt_reg) = 0x0; tc_wmb();
623 REG(vdac, bt_reg) = 0x0; tc_wmb();
624 REG(vdac, bt_reg) = 0x0; tc_wmb();
625 REG(vdac, bt_reg) = 0x0; tc_wmb();
626 REG(vdac, bt_reg) = 0x0; tc_wmb();
627 REG(vdac, bt_reg) = 0x0; tc_wmb();
628 REG(vdac, bt_reg) = 0x0; tc_wmb();
629 REG(vdac, bt_reg) = 0x0; tc_wmb();
630 REG(vdac, bt_reg) = 0x0; tc_wmb();
631 REG(vdac, bt_reg) = 0x0; tc_wmb();
632 REG(vdac, bt_reg) = 0x0; tc_wmb();
633 REG(vdac, bt_reg) = 0x0; tc_wmb();
634
635 /* build sane colormap */
636 SELECT(vdac, 0);
637 p = rasops_cmap;
638 for (i = 0; i < CMAP_SIZE; i++, p += 3) {
639 REG(vdac, bt_cmap) = p[0]; tc_wmb();
640 REG(vdac, bt_cmap) = p[1]; tc_wmb();
641 REG(vdac, bt_cmap) = p[2]; tc_wmb();
642 }
643
644 /* clear out cursor image */
645 SELECT(vdac, BT459_IREG_CRAM_BASE);
646 for (i = 0; i < 1024; i++)
647 REG(vdac, bt_reg) = 0xff; tc_wmb();
648
649 /*
650 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
651 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for
652 * image color. CCOLOR_1 will be never used.
653 */
654 SELECT(vdac, BT459_IREG_CCOLOR_1);
655 REG(vdac, bt_reg) = 0xff; tc_wmb();
656 REG(vdac, bt_reg) = 0xff; tc_wmb();
657 REG(vdac, bt_reg) = 0xff; tc_wmb();
658
659 REG(vdac, bt_reg) = 0; tc_wmb();
660 REG(vdac, bt_reg) = 0; tc_wmb();
661 REG(vdac, bt_reg) = 0; tc_wmb();
662
663 REG(vdac, bt_reg) = 0xff; tc_wmb();
664 REG(vdac, bt_reg) = 0xff; tc_wmb();
665 REG(vdac, bt_reg) = 0xff; tc_wmb();
666 }
667
668 static int
669 get_cmap(sc, p)
670 struct cfb_softc *sc;
671 struct wsdisplay_cmap *p;
672 {
673 u_int index = p->index, count = p->count;
674 int error;
675
676 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
677 return (EINVAL);
678
679 error = copyout(&sc->sc_cmap.r[index], p->red, count);
680 if (error)
681 return error;
682 error = copyout(&sc->sc_cmap.g[index], p->green, count);
683 if (error)
684 return error;
685 error = copyout(&sc->sc_cmap.b[index], p->blue, count);
686 return error;
687 }
688
689 static int
690 set_cmap(sc, p)
691 struct cfb_softc *sc;
692 struct wsdisplay_cmap *p;
693 {
694 struct hwcmap256 cmap;
695 u_int index = p->index, count = p->count;
696 int error;
697
698 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
699 return (EINVAL);
700
701 error = copyin(p->red, &cmap.r[index], count);
702 if (error)
703 return error;
704 error = copyin(p->green, &cmap.g[index], count);
705 if (error)
706 return error;
707 error = copyin(p->blue, &cmap.b[index], count);
708 if (error)
709 return error;
710 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
711 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
712 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
713 sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
714 return (0);
715 }
716
717 static int
718 set_cursor(sc, p)
719 struct cfb_softc *sc;
720 struct wsdisplay_cursor *p;
721 {
722 #define cc (&sc->sc_cursor)
723 u_int v, index = 0, count = 0, icount = 0;
724 uint8_t r[2], g[2], b[2], image[512], mask[512];
725 int error;
726
727 v = p->which;
728 if (v & WSDISPLAY_CURSOR_DOCMAP) {
729 index = p->cmap.index;
730 count = p->cmap.count;
731 if (index >= 2 || (index + count) > 2)
732 return (EINVAL);
733 error = copyin(p->cmap.red, &r[index], count);
734 if (error)
735 return error;
736 error = copyin(p->cmap.green, &g[index], count);
737 if (error)
738 return error;
739 error = copyin(p->cmap.blue, &b[index], count);
740 if (error)
741 return error;
742 }
743 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
744 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
745 return (EINVAL);
746 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
747 error = copyin(p->image, image, icount);
748 if (error)
749 return error;
750 error = copyin(p->mask, mask, icount);
751 if (error)
752 return error;
753 }
754
755 if (v & WSDISPLAY_CURSOR_DOCUR)
756 sc->sc_curenb = p->enable;
757 if (v & WSDISPLAY_CURSOR_DOPOS)
758 set_curpos(sc, &p->pos);
759 if (v & WSDISPLAY_CURSOR_DOHOT)
760 cc->cc_hot = p->hot;
761 if (v & WSDISPLAY_CURSOR_DOCMAP) {
762 memcpy(&cc->cc_color[index], &r[index], count);
763 memcpy(&cc->cc_color[index + 2], &g[index], count);
764 memcpy(&cc->cc_color[index + 4], &b[index], count);
765 }
766 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
767 cc->cc_size = p->size;
768 memset(cc->cc_image, 0, sizeof cc->cc_image);
769 memcpy(cc->cc_image, image, icount);
770 memset(cc->cc_mask, 0, sizeof cc->cc_mask);
771 memcpy(cc->cc_mask, mask, icount);
772 }
773 sc->sc_changed |= v;
774
775 return (0);
776 #undef cc
777 }
778
779 static int
780 get_cursor(sc, p)
781 struct cfb_softc *sc;
782 struct wsdisplay_cursor *p;
783 {
784 return (EPASSTHROUGH); /* XXX */
785 }
786
787 static void
788 set_curpos(sc, curpos)
789 struct cfb_softc *sc;
790 struct wsdisplay_curpos *curpos;
791 {
792 struct rasops_info *ri = sc->sc_ri;
793 int x = curpos->x, y = curpos->y;
794
795 if (y < 0)
796 y = 0;
797 else if (y > ri->ri_height)
798 y = ri->ri_height;
799 if (x < 0)
800 x = 0;
801 else if (x > ri->ri_width)
802 x = ri->ri_width;
803 sc->sc_cursor.cc_pos.x = x;
804 sc->sc_cursor.cc_pos.y = y;
805 }
806