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