cfb.c revision 1.54 1 /* $NetBSD: cfb.c,v 1.54 2008/05/26 10:31:22 nisimura 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.54 2008/05/26 10:31:22 nisimura 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 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(struct device *, struct cfdata *, void *);
141 static void cfbattach(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(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(void *, void *, u_long, void *, int, struct lwp *);
166 static paddr_t cfbmmap(void *, void *, off_t, int);
167
168 static int cfb_alloc_screen(void *, const struct wsscreen_descr *,
169 void **, int *, int *, long *);
170 static void cfb_free_screen(void *, void *);
171 static int cfb_show_screen(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(tc_addr_t);
184 static int cfbintr(void *);
185 static void cfbhwinit(void *);
186 static void cfb_cmap_init(struct cfb_softc *);
187
188 static int get_cmap(struct cfb_softc *, struct wsdisplay_cmap *);
189 static int set_cmap(struct cfb_softc *, struct wsdisplay_cmap *);
190 static int set_cursor(struct cfb_softc *, struct wsdisplay_cursor *);
191 static int get_cursor(struct cfb_softc *, struct wsdisplay_cursor *);
192 static void set_curpos(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(struct device *parent, struct cfdata *match, void *aux)
238 {
239 struct tc_attach_args *ta = aux;
240
241 if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
242 return (0);
243
244 return (1);
245 }
246
247 static void
248 cfbattach(struct device *parent, struct device *self, void *aux)
249 {
250 struct cfb_softc *sc = device_private(self);
251 struct tc_attach_args *ta = aux;
252 struct rasops_info *ri;
253 struct wsemuldisplaydev_attach_args waa;
254 int console;
255
256 console = (ta->ta_addr == cfb_consaddr);
257 if (console) {
258 sc->sc_ri = ri = &cfb_console_ri;
259 sc->nscreens = 1;
260 }
261 else {
262 MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
263 M_DEVBUF, M_NOWAIT);
264 if (ri == NULL) {
265 printf(": can't alloc memory\n");
266 return;
267 }
268 memset(ri, 0, sizeof(struct rasops_info));
269
270 ri->ri_hw = (void *)ta->ta_addr;
271 cfb_common_init(ri);
272 sc->sc_ri = ri;
273 }
274 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
275
276 cfb_cmap_init(sc);
277
278 sc->sc_vaddr = ta->ta_addr;
279 sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
280 sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
281 sc->sc_blanked = sc->sc_curenb = 0;
282
283 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
284
285 /* clear any pending interrupts */
286 *(volatile u_int8_t *)((char *)ri->ri_hw + CX_OFFSET_IREQ) = 0;
287
288 waa.console = console;
289 waa.scrdata = &cfb_screenlist;
290 waa.accessops = &cfb_accessops;
291 waa.accesscookie = sc;
292
293 config_found(self, &waa, wsemuldisplaydevprint);
294 }
295
296 static void
297 cfb_cmap_init(struct cfb_softc *sc)
298 {
299 struct hwcmap256 *cm;
300 const u_int8_t *p;
301 int index;
302
303 cm = &sc->sc_cmap;
304 p = rasops_cmap;
305 for (index = 0; index < CMAP_SIZE; index++, p += 3) {
306 cm->r[index] = p[0];
307 cm->g[index] = p[1];
308 cm->b[index] = p[2];
309 }
310 }
311
312 static void
313 cfb_common_init(struct rasops_info *ri)
314 {
315 char *base;
316 int cookie;
317
318 base = (void *)ri->ri_hw;
319
320 /* initialize colormap and cursor hardware */
321 cfbhwinit(base);
322
323 ri->ri_flg = RI_CENTER;
324 ri->ri_depth = 8;
325 ri->ri_width = 1024;
326 ri->ri_height = 864;
327 ri->ri_stride = 1024;
328 ri->ri_bits = base + CX_FB_OFFSET;
329
330 /* clear the screen */
331 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
332
333 wsfont_init();
334 /* prefer 12 pixel wide font */
335 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
336 WSDISPLAY_FONTORDER_L2R);
337 if (cookie <= 0)
338 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
339 WSDISPLAY_FONTORDER_L2R);
340 if (cookie <= 0) {
341 printf("cfb: font table is empty\n");
342 return;
343 }
344
345 if (wsfont_lock(cookie, &ri->ri_font)) {
346 printf("cfb: couldn't lock font\n");
347 return;
348 }
349 ri->ri_wsfcookie = cookie;
350
351 rasops_init(ri, 34, 80);
352
353 /* XXX shouldn't be global */
354 cfb_stdscreen.nrows = ri->ri_rows;
355 cfb_stdscreen.ncols = ri->ri_cols;
356 cfb_stdscreen.textops = &ri->ri_ops;
357 cfb_stdscreen.capabilities = ri->ri_caps;
358 }
359
360 static int
361 cfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
362 {
363 struct cfb_softc *sc = v;
364 struct rasops_info *ri = sc->sc_ri;
365 int turnoff, s;
366
367 switch (cmd) {
368 case WSDISPLAYIO_GTYPE:
369 *(u_int *)data = WSDISPLAY_TYPE_CFB;
370 return (0);
371
372 case WSDISPLAYIO_GINFO:
373 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
374 wsd_fbip->height = ri->ri_height;
375 wsd_fbip->width = ri->ri_width;
376 wsd_fbip->depth = ri->ri_depth;
377 wsd_fbip->cmsize = CMAP_SIZE;
378 #undef fbt
379 return (0);
380
381 case WSDISPLAYIO_GETCMAP:
382 return get_cmap(sc, (struct wsdisplay_cmap *)data);
383
384 case WSDISPLAYIO_PUTCMAP:
385 return set_cmap(sc, (struct wsdisplay_cmap *)data);
386
387 case WSDISPLAYIO_SVIDEO:
388 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
389 if (sc->sc_blanked != turnoff) {
390 sc->sc_blanked = turnoff;
391 /* XXX later XXX */
392 }
393 return (0);
394
395 case WSDISPLAYIO_GVIDEO:
396 *(u_int *)data = sc->sc_blanked ?
397 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
398 return (0);
399
400 case WSDISPLAYIO_GCURPOS:
401 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
402 return (0);
403
404 case WSDISPLAYIO_SCURPOS:
405 s = spltty();
406 set_curpos(sc, (struct wsdisplay_curpos *)data);
407 sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
408 splx(s);
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 case WSDISPLAYIO_SMODE:
423 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
424 s = spltty();
425 cfb_cmap_init(sc);
426 sc->sc_curenb = 0;
427 sc->sc_blanked = 0;
428 sc->sc_changed |= (WSDISPLAY_CURSOR_DOCUR |
429 WSDISPLAY_CMAP_DOLUT);
430 splx(s);
431 }
432 return (0);
433 }
434 return EPASSTHROUGH;
435 }
436
437 paddr_t
438 cfbmmap(void *v, void *vs, off_t offset, int prot)
439 {
440 struct cfb_softc *sc = v;
441
442 if (offset >= CX_FB_SIZE || offset < 0)
443 return (-1);
444 return machine_btop(sc->sc_vaddr + CX_FB_OFFSET + offset);
445 }
446
447 static int
448 cfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
449 int *curxp, int *curyp, long *attrp)
450 {
451 struct cfb_softc *sc = v;
452 struct rasops_info *ri = sc->sc_ri;
453 long defattr;
454
455 if (sc->nscreens > 0)
456 return (ENOMEM);
457
458 *cookiep = ri; /* one and only for now */
459 *curxp = 0;
460 *curyp = 0;
461 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
462 *attrp = defattr;
463 sc->nscreens++;
464 return (0);
465 }
466
467 static void
468 cfb_free_screen(void *v, void *cookie)
469 {
470 struct cfb_softc *sc = v;
471
472 if (sc->sc_ri == &cfb_console_ri)
473 panic("cfb_free_screen: console");
474
475 sc->nscreens--;
476 }
477
478 static int
479 cfb_show_screen(void *v, void *cookie, int waitok,
480 void (*cb)(void *, int, int), void *cbarg)
481 {
482
483 return (0);
484 }
485
486 /* EXPORT */ int
487 cfb_cnattach(tc_addr_t addr)
488 {
489 struct rasops_info *ri;
490 long defattr;
491
492 ri = &cfb_console_ri;
493 ri->ri_hw = (void *)addr;
494 cfb_common_init(ri);
495 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
496 wsdisplay_cnattach(&cfb_stdscreen, ri, 0, 0, defattr);
497 cfb_consaddr = addr;
498 return(0);
499 }
500
501 static int
502 cfbintr(void *arg)
503 {
504 struct cfb_softc *sc = arg;
505 char *base, *vdac;
506 int v;
507
508 base = (void *)sc->sc_ri->ri_hw;
509 *(u_int8_t *)(base + CX_OFFSET_IREQ) = 0;
510 if (sc->sc_changed == 0)
511 return (1);
512
513 vdac = base + CX_BT459_OFFSET;
514 v = sc->sc_changed;
515 if (v & WSDISPLAY_CURSOR_DOCUR) {
516 VDACSELECT(vdac, BT459_IREG_CCR);
517 REGWRITE32(vdac, bt_reg, (sc->sc_curenb) ? 0xc0 : 0x00);
518 }
519 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
520 int x, y;
521
522 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
523 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
524
525 x += sc->sc_cursor.cc_magic.x;
526 y += sc->sc_cursor.cc_magic.y;
527
528 VDACSELECT(vdac, BT459_IREG_CURSOR_X_LOW);
529 REGWRITE32(vdac, bt_reg, x);
530 REGWRITE32(vdac, bt_reg, x >> 8);
531 REGWRITE32(vdac, bt_reg, y);
532 REGWRITE32(vdac, bt_reg, y >> 8);
533 }
534 if (v & WSDISPLAY_CURSOR_DOCMAP) {
535 u_int8_t *cp = sc->sc_cursor.cc_color;
536
537 VDACSELECT(vdac, BT459_IREG_CCOLOR_2);
538 REGWRITE32(vdac, bt_reg, cp[1]);
539 REGWRITE32(vdac, bt_reg, cp[3]);
540 REGWRITE32(vdac, bt_reg, cp[5]);
541
542 REGWRITE32(vdac, bt_reg, cp[0]);
543 REGWRITE32(vdac, bt_reg, cp[2]);
544 REGWRITE32(vdac, bt_reg, cp[4]);
545 }
546 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
547 u_int8_t *ip, *mp, img, msk;
548 u_int8_t u;
549 int bcnt;
550
551 ip = (u_int8_t *)sc->sc_cursor.cc_image;
552 mp = (u_int8_t *)sc->sc_cursor.cc_mask;
553
554 bcnt = 0;
555 VDACSELECT(vdac, BT459_IREG_CRAM_BASE+0);
556 /* 64 pixel scan line is consisted with 16 byte cursor ram */
557 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
558 /* pad right half 32 pixel when smaller than 33 */
559 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
560 REGWRITE32(vdac, bt_reg, 0);
561 REGWRITE32(vdac, bt_reg, 0);
562 }
563 else {
564 img = *ip++;
565 msk = *mp++;
566 img &= msk; /* cookie off image */
567 u = (msk & 0x0f) << 4 | (img & 0x0f);
568 REGWRITE32(vdac, bt_reg, shuffle[u]);
569 u = (msk & 0xf0) | (img & 0xf0) >> 4;
570 REGWRITE32(vdac, bt_reg, shuffle[u]);
571 }
572 bcnt += 2;
573 }
574 /* pad unoccupied scan lines */
575 while (bcnt < CURSOR_MAX_SIZE * 16) {
576 REGWRITE32(vdac, bt_reg, 0);
577 REGWRITE32(vdac, bt_reg, 0);
578 bcnt += 2;
579 }
580 }
581 if (v & WSDISPLAY_CMAP_DOLUT) {
582 struct hwcmap256 *cm = &sc->sc_cmap;
583 int index;
584
585 VDACSELECT(vdac, 0);
586 for (index = 0; index < CMAP_SIZE; index++) {
587 REGWRITE32(vdac, bt_cmap, cm->r[index]);
588 REGWRITE32(vdac, bt_cmap, cm->g[index]);
589 REGWRITE32(vdac, bt_cmap, cm->b[index]);
590 }
591 }
592 sc->sc_changed = 0;
593 return (1);
594 }
595
596 static void
597 cfbhwinit(void *cfbbase)
598 {
599 char *vdac = (char *)cfbbase + CX_BT459_OFFSET;
600 const u_int8_t *p;
601 int i;
602
603 VDACSELECT(vdac, BT459_IREG_COMMAND_0);
604 REGWRITE32(vdac, bt_reg, 0x40); /* CMD0 */
605 REGWRITE32(vdac, bt_reg, 0x0); /* CMD1 */
606 REGWRITE32(vdac, bt_reg, 0xc0); /* CMD2 */
607 REGWRITE32(vdac, bt_reg, 0xff); /* PRM */
608 REGWRITE32(vdac, bt_reg, 0); /* 205 */
609 REGWRITE32(vdac, bt_reg, 0x0); /* PBM */
610 REGWRITE32(vdac, bt_reg, 0); /* 207 */
611 REGWRITE32(vdac, bt_reg, 0x0); /* ORM */
612 REGWRITE32(vdac, bt_reg, 0x0); /* OBM */
613 REGWRITE32(vdac, bt_reg, 0x0); /* ILV */
614 REGWRITE32(vdac, bt_reg, 0x0); /* TEST */
615
616 VDACSELECT(vdac, BT459_IREG_CCR);
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 REGWRITE32(vdac, bt_reg, 0x0);
630
631 /* build sane colormap */
632 VDACSELECT(vdac, 0);
633 p = rasops_cmap;
634 for (i = 0; i < CMAP_SIZE; i++, p += 3) {
635 REGWRITE32(vdac, bt_cmap, p[0]);
636 REGWRITE32(vdac, bt_cmap, p[1]);
637 REGWRITE32(vdac, bt_cmap, p[2]);
638 }
639
640 /* clear out cursor image */
641 VDACSELECT(vdac, BT459_IREG_CRAM_BASE);
642 for (i = 0; i < 1024; i++)
643 REGWRITE32(vdac, bt_reg, 0xff);
644
645 /*
646 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
647 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for
648 * image color. CCOLOR_1 will be never used.
649 */
650 VDACSELECT(vdac, BT459_IREG_CCOLOR_1);
651 REGWRITE32(vdac, bt_reg, 0xff);
652 REGWRITE32(vdac, bt_reg, 0xff);
653 REGWRITE32(vdac, bt_reg, 0xff);
654
655 REGWRITE32(vdac, bt_reg, 0);
656 REGWRITE32(vdac, bt_reg, 0);
657 REGWRITE32(vdac, bt_reg, 0);
658
659 REGWRITE32(vdac, bt_reg, 0xff);
660 REGWRITE32(vdac, bt_reg, 0xff);
661 REGWRITE32(vdac, bt_reg, 0xff);
662 }
663
664 static int
665 get_cmap(struct cfb_softc *sc, struct wsdisplay_cmap *p)
666 {
667 u_int index = p->index, count = p->count;
668 int error;
669
670 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
671 return (EINVAL);
672
673 error = copyout(&sc->sc_cmap.r[index], p->red, count);
674 if (error)
675 return error;
676 error = copyout(&sc->sc_cmap.g[index], p->green, count);
677 if (error)
678 return error;
679 error = copyout(&sc->sc_cmap.b[index], p->blue, count);
680 return error;
681 }
682
683 static int
684 set_cmap(struct cfb_softc *sc, struct wsdisplay_cmap *p)
685 {
686 struct hwcmap256 cmap;
687 u_int index = p->index, count = p->count;
688 int error, s;
689
690 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
691 return (EINVAL);
692
693 error = copyin(p->red, &cmap.r[index], count);
694 if (error)
695 return error;
696 error = copyin(p->green, &cmap.g[index], count);
697 if (error)
698 return error;
699 error = copyin(p->blue, &cmap.b[index], count);
700 if (error)
701 return error;
702 s = spltty();
703 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
704 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
705 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
706 sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
707 splx(s);
708 return (0);
709 }
710
711 static int
712 set_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p)
713 {
714 #define cc (&sc->sc_cursor)
715 u_int v, index = 0, count = 0, icount = 0;
716 uint8_t r[2], g[2], b[2], image[512], mask[512];
717 int error, s;
718
719 v = p->which;
720 if (v & WSDISPLAY_CURSOR_DOCMAP) {
721 index = p->cmap.index;
722 count = p->cmap.count;
723 if (index >= 2 || (index + count) > 2)
724 return (EINVAL);
725 error = copyin(p->cmap.red, &r[index], count);
726 if (error)
727 return error;
728 error = copyin(p->cmap.green, &g[index], count);
729 if (error)
730 return error;
731 error = copyin(p->cmap.blue, &b[index], count);
732 if (error)
733 return error;
734 }
735 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
736 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
737 return (EINVAL);
738 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
739 error = copyin(p->image, image, icount);
740 if (error)
741 return error;
742 error = copyin(p->mask, mask, icount);
743 if (error)
744 return error;
745 }
746
747 s = spltty();
748 if (v & WSDISPLAY_CURSOR_DOCUR)
749 sc->sc_curenb = p->enable;
750 if (v & WSDISPLAY_CURSOR_DOPOS)
751 set_curpos(sc, &p->pos);
752 if (v & WSDISPLAY_CURSOR_DOHOT)
753 cc->cc_hot = p->hot;
754 if (v & WSDISPLAY_CURSOR_DOCMAP) {
755 memcpy(&cc->cc_color[index], &r[index], count);
756 memcpy(&cc->cc_color[index + 2], &g[index], count);
757 memcpy(&cc->cc_color[index + 4], &b[index], count);
758 }
759 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
760 cc->cc_size = p->size;
761 memset(cc->cc_image, 0, sizeof cc->cc_image);
762 memcpy(cc->cc_image, image, icount);
763 memset(cc->cc_mask, 0, sizeof cc->cc_mask);
764 memcpy(cc->cc_mask, mask, icount);
765 }
766 sc->sc_changed |= v;
767 splx(s);
768
769 return (0);
770 #undef cc
771 }
772
773 static int
774 get_cursor(struct cfb_softc *sc, struct wsdisplay_cursor *p)
775 {
776 return (EPASSTHROUGH); /* XXX */
777 }
778
779 static void
780 set_curpos(struct cfb_softc *sc, struct wsdisplay_curpos *curpos)
781 {
782 struct rasops_info *ri = sc->sc_ri;
783 int x = curpos->x, y = curpos->y;
784
785 if (y < 0)
786 y = 0;
787 else if (y > ri->ri_height)
788 y = ri->ri_height;
789 if (x < 0)
790 x = 0;
791 else if (x > ri->ri_width)
792 x = ri->ri_width;
793 sc->sc_cursor.cc_pos.x = x;
794 sc->sc_cursor.cc_pos.y = y;
795 }
796