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