cfb.c revision 1.58 1 /* $NetBSD: cfb.c,v 1.58 2010/05/15 07:01:37 tsutsui 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.58 2010/05/15 07:01:37 tsutsui 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 * uint8_t u0;
72 * uint8_t u1;
73 * uint8_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 * uint32_t bt_lo;
80 * uint32_t bt_hi;
81 * uint32_t bt_reg;
82 * uint32_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 uint32_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 uint8_t r[CMAP_SIZE];
103 uint8_t g[CMAP_SIZE];
104 uint8_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 uint8_t cc_color[6];
114 uint64_t cc_image[CURSOR_MAX_SIZE];
115 uint64_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 uint8_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 ri = malloc(sizeof(struct rasops_info),
262 M_DEVBUF, M_NOWAIT|M_ZERO);
263 if (ri == NULL) {
264 printf(": can't alloc memory\n");
265 return;
266 }
267
268 ri->ri_hw = (void *)ta->ta_addr;
269 cfb_common_init(ri);
270 sc->sc_ri = ri;
271 }
272 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
273
274 cfb_cmap_init(sc);
275
276 sc->sc_vaddr = ta->ta_addr;
277 sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
278 sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
279 sc->sc_blanked = sc->sc_curenb = 0;
280
281 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
282
283 /* clear any pending interrupts */
284 *(volatile uint8_t *)((char *)ri->ri_hw + CX_OFFSET_IREQ) = 0;
285
286 waa.console = console;
287 waa.scrdata = &cfb_screenlist;
288 waa.accessops = &cfb_accessops;
289 waa.accesscookie = sc;
290
291 config_found(self, &waa, wsemuldisplaydevprint);
292 }
293
294 static void
295 cfb_cmap_init(struct cfb_softc *sc)
296 {
297 struct hwcmap256 *cm;
298 const uint8_t *p;
299 int index;
300
301 cm = &sc->sc_cmap;
302 p = rasops_cmap;
303 for (index = 0; index < CMAP_SIZE; index++, p += 3) {
304 cm->r[index] = p[0];
305 cm->g[index] = p[1];
306 cm->b[index] = p[2];
307 }
308 }
309
310 static void
311 cfb_common_init(struct rasops_info *ri)
312 {
313 char *base;
314 int cookie;
315
316 base = (void *)ri->ri_hw;
317
318 /* initialize colormap and cursor hardware */
319 cfbhwinit(base);
320
321 ri->ri_flg = RI_CENTER;
322 if (ri == &cfb_console_ri)
323 ri->ri_flg |= RI_NO_AUTO;
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 *(uint8_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 uint8_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 uint8_t *ip, *mp, img, msk;
548 uint8_t u;
549 int bcnt;
550
551 ip = (uint8_t *)sc->sc_cursor.cc_image;
552 mp = (uint8_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 uint8_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