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