cfb.c revision 1.55 1 /* $NetBSD: cfb.c,v 1.55 2008/07/09 13:19:33 joerg Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: cfb.c,v 1.55 2008/07/09 13:19:33 joerg Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
39 #include <sys/malloc.h>
40 #include <sys/buf.h>
41 #include <sys/ioctl.h>
42
43 #include <sys/bus.h>
44 #include <sys/intr.h>
45
46 #include <dev/wscons/wsconsio.h>
47 #include <dev/wscons/wsdisplayvar.h>
48
49 #include <dev/rasops/rasops.h>
50 #include <dev/wsfont/wsfont.h>
51
52 #include <dev/tc/tcvar.h>
53 #include <dev/ic/bt459reg.h>
54
55 #include <uvm/uvm_extern.h>
56
57 #if defined(pmax)
58 #define machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
59 #endif
60
61 #if defined(alpha)
62 #define machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
63 #endif
64
65 /*
66 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have
67 * obscure register layout such as 2nd and 3rd Bt459 registers are
68 * adjacent each other in a word, i.e.,
69 * struct bt459triplet {
70 * struct {
71 * u_int8_t u0;
72 * u_int8_t u1;
73 * u_int8_t u2;
74 * unsigned :8;
75 * } bt_lo;
76 * ...
77 * Although CX has single Bt459, 32bit R/W can be done w/o any trouble.
78 * struct bt459reg {
79 * u_int32_t bt_lo;
80 * u_int32_t bt_hi;
81 * u_int32_t bt_reg;
82 * u_int32_t bt_cmap;
83 * };
84 */
85
86 /* Bt459 hardware registers, memory-mapped in 32bit stride */
87 #define bt_lo 0x0
88 #define bt_hi 0x4
89 #define bt_reg 0x8
90 #define bt_cmap 0xc
91
92 #define REGWRITE32(p,i,v) do { \
93 *(volatile u_int32_t *)((p) + (i)) = (v); tc_wmb(); \
94 } while (0)
95 #define VDACSELECT(p,r) do { \
96 REGWRITE32(p, bt_lo, 0xff & (r)); \
97 REGWRITE32(p, bt_hi, 0x0f & ((r)>>8)); \
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 vaddr_t sc_vaddr;
120 size_t sc_size;
121 struct rasops_info *sc_ri;
122 struct hwcmap256 sc_cmap; /* software copy of colormap */
123 struct hwcursor64 sc_cursor; /* software copy of cursor */
124 int sc_blanked;
125 int sc_curenb; /* cursor sprite enabled */
126 int sc_changed; /* need update of hardware */
127 #define WSDISPLAY_CMAP_DOLUT 0x20
128 int nscreens;
129 };
130
131 #define CX_MAGIC_X 220
132 #define CX_MAGIC_Y 35
133
134 #define CX_FB_OFFSET 0x000000
135 #define CX_FB_SIZE 0x100000
136 #define CX_BT459_OFFSET 0x200000
137 #define CX_OFFSET_IREQ 0x300000 /* Interrupt req. control */
138
139 static int cfbmatch(device_t, cfdata_t, void *);
140 static void cfbattach(device_t, device_t, void *);
141
142 CFATTACH_DECL_NEW(cfb, sizeof(struct cfb_softc),
143 cfbmatch, cfbattach, NULL, NULL);
144
145 static void cfb_common_init(struct rasops_info *);
146 static struct rasops_info cfb_console_ri;
147 static tc_addr_t cfb_consaddr;
148
149 static struct wsscreen_descr cfb_stdscreen = {
150 "std", 0, 0,
151 0, /* textops */
152 0, 0,
153 WSSCREEN_REVERSE
154 };
155
156 static const struct wsscreen_descr *_cfb_scrlist[] = {
157 &cfb_stdscreen,
158 };
159
160 static const struct wsscreen_list cfb_screenlist = {
161 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
162 };
163
164 static int cfbioctl(void *, void *, u_long, void *, int, struct lwp *);
165 static paddr_t cfbmmap(void *, void *, off_t, int);
166
167 static int cfb_alloc_screen(void *, const struct wsscreen_descr *,
168 void **, int *, int *, long *);
169 static void cfb_free_screen(void *, void *);
170 static int cfb_show_screen(void *, void *, int,
171 void (*) (void *, int, int), void *);
172
173 static const struct wsdisplay_accessops cfb_accessops = {
174 cfbioctl,
175 cfbmmap,
176 cfb_alloc_screen,
177 cfb_free_screen,
178 cfb_show_screen,
179 0 /* load_font */
180 };
181
182 int cfb_cnattach(tc_addr_t);
183 static int cfbintr(void *);
184 static void cfbhwinit(void *);
185 static void cfb_cmap_init(struct cfb_softc *);
186
187 static int get_cmap(struct cfb_softc *, struct wsdisplay_cmap *);
188 static int set_cmap(struct cfb_softc *, struct wsdisplay_cmap *);
189 static int set_cursor(struct cfb_softc *, struct wsdisplay_cursor *);
190 static int get_cursor(struct cfb_softc *, struct wsdisplay_cursor *);
191 static void set_curpos(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(device_t parent, cfdata_t match, void *aux)
237 {
238 struct tc_attach_args *ta = aux;
239
240 if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
241 return (0);
242
243 return (1);
244 }
245
246 static void
247 cfbattach(device_t parent, device_t self, void *aux)
248 {
249 struct cfb_softc *sc = device_private(self);
250 struct tc_attach_args *ta = aux;
251 struct rasops_info *ri;
252 struct wsemuldisplaydev_attach_args waa;
253 int console;
254
255 console = (ta->ta_addr == cfb_consaddr);
256 if (console) {
257 sc->sc_ri = ri = &cfb_console_ri;
258 sc->nscreens = 1;
259 }
260 else {
261 MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
262 M_DEVBUF, M_NOWAIT);
263 if (ri == NULL) {
264 printf(": can't alloc memory\n");
265 return;
266 }
267 memset(ri, 0, sizeof(struct rasops_info));
268
269 ri->ri_hw = (void *)ta->ta_addr;
270 cfb_common_init(ri);
271 sc->sc_ri = ri;
272 }
273 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
274
275 cfb_cmap_init(sc);
276
277 sc->sc_vaddr = ta->ta_addr;
278 sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
279 sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
280 sc->sc_blanked = sc->sc_curenb = 0;
281
282 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
283
284 /* clear any pending interrupts */
285 *(volatile u_int8_t *)((char *)ri->ri_hw + CX_OFFSET_IREQ) = 0;
286
287 waa.console = console;
288 waa.scrdata = &cfb_screenlist;
289 waa.accessops = &cfb_accessops;
290 waa.accesscookie = sc;
291
292 config_found(self, &waa, wsemuldisplaydevprint);
293 }
294
295 static void
296 cfb_cmap_init(struct cfb_softc *sc)
297 {
298 struct hwcmap256 *cm;
299 const u_int8_t *p;
300 int index;
301
302 cm = &sc->sc_cmap;
303 p = rasops_cmap;
304 for (index = 0; index < CMAP_SIZE; index++, p += 3) {
305 cm->r[index] = p[0];
306 cm->g[index] = p[1];
307 cm->b[index] = p[2];
308 }
309 }
310
311 static void
312 cfb_common_init(struct rasops_info *ri)
313 {
314 char *base;
315 int cookie;
316
317 base = (void *)ri->ri_hw;
318
319 /* initialize colormap and cursor hardware */
320 cfbhwinit(base);
321
322 ri->ri_flg = RI_CENTER;
323 ri->ri_depth = 8;
324 ri->ri_width = 1024;
325 ri->ri_height = 864;
326 ri->ri_stride = 1024;
327 ri->ri_bits = base + CX_FB_OFFSET;
328
329 /* clear the screen */
330 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
331
332 wsfont_init();
333 /* prefer 12 pixel wide font */
334 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
335 WSDISPLAY_FONTORDER_L2R);
336 if (cookie <= 0)
337 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
338 WSDISPLAY_FONTORDER_L2R);
339 if (cookie <= 0) {
340 printf("cfb: font table is empty\n");
341 return;
342 }
343
344 if (wsfont_lock(cookie, &ri->ri_font)) {
345 printf("cfb: couldn't lock font\n");
346 return;
347 }
348 ri->ri_wsfcookie = cookie;
349
350 rasops_init(ri, 34, 80);
351
352 /* XXX shouldn't be global */
353 cfb_stdscreen.nrows = ri->ri_rows;
354 cfb_stdscreen.ncols = ri->ri_cols;
355 cfb_stdscreen.textops = &ri->ri_ops;
356 cfb_stdscreen.capabilities = ri->ri_caps;
357 }
358
359 static int
360 cfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
361 {
362 struct cfb_softc *sc = v;
363 struct rasops_info *ri = sc->sc_ri;
364 int turnoff, s;
365
366 switch (cmd) {
367 case WSDISPLAYIO_GTYPE:
368 *(u_int *)data = WSDISPLAY_TYPE_CFB;
369 return (0);
370
371 case WSDISPLAYIO_GINFO:
372 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
373 wsd_fbip->height = ri->ri_height;
374 wsd_fbip->width = ri->ri_width;
375 wsd_fbip->depth = ri->ri_depth;
376 wsd_fbip->cmsize = CMAP_SIZE;
377 #undef fbt
378 return (0);
379
380 case WSDISPLAYIO_GETCMAP:
381 return get_cmap(sc, (struct wsdisplay_cmap *)data);
382
383 case WSDISPLAYIO_PUTCMAP:
384 return set_cmap(sc, (struct wsdisplay_cmap *)data);
385
386 case WSDISPLAYIO_SVIDEO:
387 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
388 if (sc->sc_blanked != turnoff) {
389 sc->sc_blanked = turnoff;
390 /* XXX later XXX */
391 }
392 return (0);
393
394 case WSDISPLAYIO_GVIDEO:
395 *(u_int *)data = sc->sc_blanked ?
396 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
397 return (0);
398
399 case WSDISPLAYIO_GCURPOS:
400 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
401 return (0);
402
403 case WSDISPLAYIO_SCURPOS:
404 s = spltty();
405 set_curpos(sc, (struct wsdisplay_curpos *)data);
406 sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
407 splx(s);
408 return (0);
409
410 case WSDISPLAYIO_GCURMAX:
411 ((struct wsdisplay_curpos *)data)->x =
412 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
413 return (0);
414
415 case WSDISPLAYIO_GCURSOR:
416 return get_cursor(sc, (struct wsdisplay_cursor *)data);
417
418 case WSDISPLAYIO_SCURSOR:
419 return set_cursor(sc, (struct wsdisplay_cursor *)data);
420
421 case WSDISPLAYIO_SMODE:
422 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
423 s = spltty();
424 cfb_cmap_init(sc);
425 sc->sc_curenb = 0;
426 sc->sc_blanked = 0;
427 sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
428 WSDISPLAY_CMAP_DOLUT);
429 splx(s);
430 }
431 return (0);
432 }
433 return EPASSTHROUGH;
434 }
435
436 paddr_t
437 cfbmmap(void *v, void *vs, off_t offset, int prot)
438 {
439 struct cfb_softc *sc = v;
440
441 if (offset >= CX_FB_SIZE || offset < 0)
442 return (-1);
443 return machine_btop(sc->sc_vaddr + CX_FB_OFFSET + offset);
444 }
445
446 static int
447 cfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
448 int *curxp, int *curyp, long *attrp)
449 {
450 struct cfb_softc *sc = v;
451 struct rasops_info *ri = sc->sc_ri;
452 long defattr;
453
454 if (sc->nscreens > 0)
455 return (ENOMEM);
456
457 *cookiep = ri; /* one and only for now */
458 *curxp = 0;
459 *curyp = 0;
460 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
461 *attrp = defattr;
462 sc->nscreens++;
463 return (0);
464 }
465
466 static void
467 cfb_free_screen(void *v, void *cookie)
468 {
469 struct cfb_softc *sc = v;
470
471 if (sc->sc_ri == &cfb_console_ri)
472 panic("cfb_free_screen: console");
473
474 sc->nscreens--;
475 }
476
477 static int
478 cfb_show_screen(void *v, void *cookie, int waitok,
479 void (*cb)(void *, int, int), void *cbarg)
480 {
481
482 return (0);
483 }
484
485 /* EXPORT */ int
486 cfb_cnattach(tc_addr_t addr)
487 {
488 struct rasops_info *ri;
489 long defattr;
490
491 ri = &cfb_console_ri;
492 ri->ri_hw = (void *)addr;
493 cfb_common_init(ri);
494 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
495 wsdisplay_cnattach(&cfb_stdscreen, ri, 0, 0, defattr);
496 cfb_consaddr = addr;
497 return(0);
498 }
499
500 static int
501 cfbintr(void *arg)
502 {
503 struct cfb_softc *sc = arg;
504 char *base, *vdac;
505 int v;
506
507 base = (void *)sc->sc_ri->ri_hw;
508 *(u_int8_t *)(base + CX_OFFSET_IREQ) = 0;
509 if (sc->sc_changed == 0)
510 return (1);
511
512 vdac = base + CX_BT459_OFFSET;
513 v = sc->sc_changed;
514 if (v & WSDISPLAY_CURSOR_DOCUR) {
515 VDACSELECT(vdac, BT459_IREG_CCR);
516 REGWRITE32(vdac, bt_reg, (sc->sc_curenb) ? 0xc0 : 0x00);
517 }
518 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
519 int x, y;
520
521 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
522 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
523
524 x += sc->sc_cursor.cc_magic.x;
525 y += sc->sc_cursor.cc_magic.y;
526
527 VDACSELECT(vdac, BT459_IREG_CURSOR_X_LOW);
528 REGWRITE32(vdac, bt_reg, x);
529 REGWRITE32(vdac, bt_reg, x >> 8);
530 REGWRITE32(vdac, bt_reg, y);
531 REGWRITE32(vdac, bt_reg, y >> 8);
532 }
533 if (v & WSDISPLAY_CURSOR_DOCMAP) {
534 u_int8_t *cp = sc->sc_cursor.cc_color;
535
536 VDACSELECT(vdac, BT459_IREG_CCOLOR_2);
537 REGWRITE32(vdac, bt_reg, cp[1]);
538 REGWRITE32(vdac, bt_reg, cp[3]);
539 REGWRITE32(vdac, bt_reg, cp[5]);
540
541 REGWRITE32(vdac, bt_reg, cp[0]);
542 REGWRITE32(vdac, bt_reg, cp[2]);
543 REGWRITE32(vdac, bt_reg, cp[4]);
544 }
545 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
546 u_int8_t *ip, *mp, img, msk;
547 u_int8_t u;
548 int bcnt;
549
550 ip = (u_int8_t *)sc->sc_cursor.cc_image;
551 mp = (u_int8_t *)sc->sc_cursor.cc_mask;
552
553 bcnt = 0;
554 VDACSELECT(vdac, BT459_IREG_CRAM_BASE+0);
555 /* 64 pixel scan line is consisted with 16 byte cursor ram */
556 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
557 /* pad right half 32 pixel when smaller than 33 */
558 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
559 REGWRITE32(vdac, bt_reg, 0);
560 REGWRITE32(vdac, bt_reg, 0);
561 }
562 else {
563 img = *ip++;
564 msk = *mp++;
565 img &= msk; /* cookie off image */
566 u = (msk & 0x0f) << 4 | (img & 0x0f);
567 REGWRITE32(vdac, bt_reg, shuffle[u]);
568 u = (msk & 0xf0) | (img & 0xf0) >> 4;
569 REGWRITE32(vdac, bt_reg, shuffle[u]);
570 }
571 bcnt += 2;
572 }
573 /* pad unoccupied scan lines */
574 while (bcnt < CURSOR_MAX_SIZE * 16) {
575 REGWRITE32(vdac, bt_reg, 0);
576 REGWRITE32(vdac, bt_reg, 0);
577 bcnt += 2;
578 }
579 }
580 if (v & WSDISPLAY_CMAP_DOLUT) {
581 struct hwcmap256 *cm = &sc->sc_cmap;
582 int index;
583
584 VDACSELECT(vdac, 0);
585 for (index = 0; index < CMAP_SIZE; index++) {
586 REGWRITE32(vdac, bt_cmap, cm->r[index]);
587 REGWRITE32(vdac, bt_cmap, cm->g[index]);
588 REGWRITE32(vdac, bt_cmap, cm->b[index]);
589 }
590 }
591 sc->sc_changed = 0;
592 return (1);
593 }
594
595 static void
596 cfbhwinit(void *cfbbase)
597 {
598 char *vdac = (char *)cfbbase + CX_BT459_OFFSET;
599 const u_int8_t *p;
600 int i;
601
602 VDACSELECT(vdac, BT459_IREG_COMMAND_0);
603 REGWRITE32(vdac, bt_reg, 0x40); /* CMD0 */
604 REGWRITE32(vdac, bt_reg, 0x0); /* CMD1 */
605 REGWRITE32(vdac, bt_reg, 0xc0); /* CMD2 */
606 REGWRITE32(vdac, bt_reg, 0xff); /* PRM */
607 REGWRITE32(vdac, bt_reg, 0); /* 205 */
608 REGWRITE32(vdac, bt_reg, 0x0); /* PBM */
609 REGWRITE32(vdac, bt_reg, 0); /* 207 */
610 REGWRITE32(vdac, bt_reg, 0x0); /* ORM */
611 REGWRITE32(vdac, bt_reg, 0x0); /* OBM */
612 REGWRITE32(vdac, bt_reg, 0x0); /* ILV */
613 REGWRITE32(vdac, bt_reg, 0x0); /* TEST */
614
615 VDACSELECT(vdac, BT459_IREG_CCR);
616 REGWRITE32(vdac, bt_reg, 0x0);
617 REGWRITE32(vdac, bt_reg, 0x0);
618 REGWRITE32(vdac, bt_reg, 0x0);
619 REGWRITE32(vdac, bt_reg, 0x0);
620 REGWRITE32(vdac, bt_reg, 0x0);
621 REGWRITE32(vdac, bt_reg, 0x0);
622 REGWRITE32(vdac, bt_reg, 0x0);
623 REGWRITE32(vdac, bt_reg, 0x0);
624 REGWRITE32(vdac, bt_reg, 0x0);
625 REGWRITE32(vdac, bt_reg, 0x0);
626 REGWRITE32(vdac, bt_reg, 0x0);
627 REGWRITE32(vdac, bt_reg, 0x0);
628 REGWRITE32(vdac, bt_reg, 0x0);
629
630 /* build sane colormap */
631 VDACSELECT(vdac, 0);
632 p = rasops_cmap;
633 for (i = 0; i < CMAP_SIZE; i++, p += 3) {
634 REGWRITE32(vdac, bt_cmap, p[0]);
635 REGWRITE32(vdac, bt_cmap, p[1]);
636 REGWRITE32(vdac, bt_cmap, p[2]);
637 }
638
639 /* clear out cursor image */
640 VDACSELECT(vdac, BT459_IREG_CRAM_BASE);
641 for (i = 0; i < 1024; i++)
642 REGWRITE32(vdac, bt_reg, 0xff);
643
644 /*
645 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
646 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for
647 * image color. CCOLOR_1 will be never used.
648 */
649 VDACSELECT(vdac, BT459_IREG_CCOLOR_1);
650 REGWRITE32(vdac, bt_reg, 0xff);
651 REGWRITE32(vdac, bt_reg, 0xff);
652 REGWRITE32(vdac, bt_reg, 0xff);
653
654 REGWRITE32(vdac, bt_reg, 0);
655 REGWRITE32(vdac, bt_reg, 0);
656 REGWRITE32(vdac, bt_reg, 0);
657
658 REGWRITE32(vdac, bt_reg, 0xff);
659 REGWRITE32(vdac, bt_reg, 0xff);
660 REGWRITE32(vdac, bt_reg, 0xff);
661 }
662
663 static int
664 get_cmap(struct cfb_softc *sc, struct wsdisplay_cmap *p)
665 {
666 u_int index = p->index, count = p->count;
667 int error;
668
669 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
670 return (EINVAL);
671
672 error = copyout(&sc->sc_cmap.r[index], p->red, count);
673 if (error)
674 return error;
675 error = copyout(&sc->sc_cmap.g[index], p->green, count);
676 if (error)
677 return error;
678 error = copyout(&sc->sc_cmap.b[index], p->blue, count);
679 return error;
680 }
681
682 static int
683 set_cmap(struct cfb_softc *sc, struct wsdisplay_cmap *p)
684 {
685 struct hwcmap256 cmap;
686 u_int index = p->index, count = p->count;
687 int error, s;
688
689 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
690 return (EINVAL);
691
692 error = copyin(p->red, &cmap.r[index], count);
693 if (error)
694 return error;
695 error = copyin(p->green, &cmap.g[index], count);
696 if (error)
697 return error;
698 error = copyin(p->blue, &cmap.b[index], count);
699 if (error)
700 return error;
701 s = spltty();
702 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
703 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
704 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
705 sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
706 splx(s);
707 return (0);
708 }
709
710 static int
711 set_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p)
712 {
713 #define cc (&sc->sc_cursor)
714 u_int v, index = 0, count = 0, icount = 0;
715 uint8_t r[2], g[2], b[2], image[512], mask[512];
716 int error, s;
717
718 v = p->which;
719 if (v & WSDISPLAY_CURSOR_DOCMAP) {
720 index = p->cmap.index;
721 count = p->cmap.count;
722 if (index >= 2 || (index + count) > 2)
723 return (EINVAL);
724 error = copyin(p->cmap.red, &r[index], count);
725 if (error)
726 return error;
727 error = copyin(p->cmap.green, &g[index], count);
728 if (error)
729 return error;
730 error = copyin(p->cmap.blue, &b[index], count);
731 if (error)
732 return error;
733 }
734 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
735 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
736 return (EINVAL);
737 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
738 error = copyin(p->image, image, icount);
739 if (error)
740 return error;
741 error = copyin(p->mask, mask, icount);
742 if (error)
743 return error;
744 }
745
746 s = spltty();
747 if (v & WSDISPLAY_CURSOR_DOCUR)
748 sc->sc_curenb = p->enable;
749 if (v & WSDISPLAY_CURSOR_DOPOS)
750 set_curpos(sc, &p->pos);
751 if (v & WSDISPLAY_CURSOR_DOHOT)
752 cc->cc_hot = p->hot;
753 if (v & WSDISPLAY_CURSOR_DOCMAP) {
754 memcpy(&cc->cc_color[index], &r[index], count);
755 memcpy(&cc->cc_color[index + 2], &g[index], count);
756 memcpy(&cc->cc_color[index + 4], &b[index], count);
757 }
758 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
759 cc->cc_size = p->size;
760 memset(cc->cc_image, 0, sizeof cc->cc_image);
761 memcpy(cc->cc_image, image, icount);
762 memset(cc->cc_mask, 0, sizeof cc->cc_mask);
763 memcpy(cc->cc_mask, mask, icount);
764 }
765 sc->sc_changed |= v;
766 splx(s);
767
768 return (0);
769 #undef cc
770 }
771
772 static int
773 get_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p)
774 {
775 return (EPASSTHROUGH); /* XXX */
776 }
777
778 static void
779 set_curpos(struct cfb_softc *sc, struct wsdisplay_curpos *curpos)
780 {
781 struct rasops_info *ri = sc->sc_ri;
782 int x = curpos->x, y = curpos->y;
783
784 if (y < 0)
785 y = 0;
786 else if (y > ri->ri_height)
787 y = ri->ri_height;
788 if (x < 0)
789 x = 0;
790 else if (x > ri->ri_width)
791 x = ri->ri_width;
792 sc->sc_cursor.cc_pos.x = x;
793 sc->sc_cursor.cc_pos.y = y;
794 }
795