cfb.c revision 1.9 1 /* $NetBSD: cfb.c,v 1.9 1999/03/24 05:51:21 mrg Exp $ */
2
3 /*
4 * Copyright (c) 1998 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> /* RCS ID & Copyright macro defns */
34
35 __KERNEL_RCSID(0, "$NetBSD: cfb.c,v 1.9 1999/03/24 05:51:21 mrg Exp $");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42 #include <sys/buf.h>
43 #include <sys/ioctl.h>
44 #include <vm/vm.h>
45
46 #include <machine/bus.h>
47 #include <machine/intr.h>
48
49 #include <dev/rcons/raster.h>
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/wscons/wscons_raster.h>
52 #include <dev/wscons/wsdisplayvar.h>
53 #include <machine/autoconf.h>
54
55 #include <dev/tc/tcvar.h>
56 #include <dev/ic/bt459reg.h>
57
58 #include <uvm/uvm_extern.h>
59
60 /* XXX BUS'IFYING XXX */
61
62 #if defined(pmax)
63 #define machine_btop(x) mips_btop(x)
64 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x)
65 #endif
66
67 #if defined(__alpha__) || defined(alpha)
68 /*
69 * Digital UNIX never supports PMAG-BA
70 */
71 #define machine_btop(x) alpha_btop(x)
72 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
73 #endif
74
75 /*
76 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have
77 * obscure register layout such as 2nd and 3rd Bt459 registers are
78 * adjacent each other in a word, i.e.,
79 * struct bt459triplet {
80 * struct {
81 * u_int8_t u0;
82 * u_int8_t u1;
83 * u_int8_t u2;
84 * unsigned :8;
85 * } bt_lo;
86 * ...
87 * Although CX has single Bt459, 32bit R/W can be done w/o any trouble.
88 */
89 struct bt459reg {
90 u_int32_t bt_lo;
91 u_int32_t bt_hi;
92 u_int32_t bt_reg;
93 u_int32_t bt_cmap;
94 };
95
96 /* XXX XXX XXX */
97
98 struct fb_devconfig {
99 vaddr_t dc_vaddr; /* memory space virtual base address */
100 paddr_t dc_paddr; /* memory space physical base address */
101 vsize_t dc_size; /* size of slot memory */
102 int dc_wid; /* width of frame buffer */
103 int dc_ht; /* height of frame buffer */
104 int dc_depth; /* depth, bits per pixel */
105 int dc_rowbytes; /* bytes in a FB scan line */
106 vaddr_t dc_videobase; /* base of flat frame buffer */
107 struct raster dc_raster; /* raster description */
108 struct rcons dc_rcons; /* raster blitter control info */
109 int dc_blanked; /* currently has video disabled */
110 };
111
112 struct hwcmap {
113 #define CMAP_SIZE 256 /* 256 R/G/B entries */
114 u_int8_t r[CMAP_SIZE];
115 u_int8_t g[CMAP_SIZE];
116 u_int8_t b[CMAP_SIZE];
117 };
118
119 struct hwcursor {
120 struct wsdisplay_curpos cc_pos;
121 struct wsdisplay_curpos cc_hot;
122 struct wsdisplay_curpos cc_size;
123 #define CURSOR_MAX_SIZE 64
124 u_int8_t cc_color[6];
125 u_int64_t cc_image[64 + 64];
126 };
127
128 struct cfb_softc {
129 struct device sc_dev;
130 struct fb_devconfig *sc_dc; /* device configuration */
131 struct hwcmap sc_cmap; /* software copy of colormap */
132 struct hwcursor sc_cursor; /* software copy of cursor */
133 int sc_curenb; /* cursor sprite enabled */
134 int sc_changed; /* need update of colormap */
135 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */
136 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */
137 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */
138 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */
139 #define DATA_ALL_CHANGED 0x0f
140 int nscreens;
141 short magic_x, magic_y; /* CX cursor location offset */
142 #define CX_MAGIC_X 220
143 #define CX_MAGIC_Y 35
144 };
145
146 #define CX_FB_OFFSET 0x000000
147 #define CX_FB_SIZE 0x100000
148 #define CX_BT459_OFFSET 0x200000
149 #define CX_OFFSET_IREQ 0x300000 /* Interrupt req. control */
150
151 int cfbmatch __P((struct device *, struct cfdata *, void *));
152 void cfbattach __P((struct device *, struct device *, void *));
153
154 struct cfattach cfb_ca = {
155 sizeof(struct cfb_softc), cfbmatch, cfbattach,
156 };
157
158 void cfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
159 struct fb_devconfig cfb_console_dc;
160 tc_addr_t cfb_consaddr;
161
162 struct wsdisplay_emulops cfb_emulops = {
163 rcons_cursor, /* could use hardware cursor; punt */
164 rcons_mapchar,
165 rcons_putchar,
166 rcons_copycols,
167 rcons_erasecols,
168 rcons_copyrows,
169 rcons_eraserows,
170 rcons_alloc_attr
171 };
172
173 struct wsscreen_descr cfb_stdscreen = {
174 "std", 0, 0,
175 &cfb_emulops,
176 0, 0,
177 0
178 };
179
180 const struct wsscreen_descr *_cfb_scrlist[] = {
181 &cfb_stdscreen,
182 };
183
184 struct wsscreen_list cfb_screenlist = {
185 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
186 };
187
188 int cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
189 int cfbmmap __P((void *, off_t, int));
190
191 int cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
192 void **, int *, int *, long *));
193 void cfb_free_screen __P((void *, void *));
194 void cfb_show_screen __P((void *, void *));
195
196 struct wsdisplay_accessops cfb_accessops = {
197 cfbioctl,
198 cfbmmap,
199 cfb_alloc_screen,
200 cfb_free_screen,
201 cfb_show_screen,
202 0 /* load_font */
203 };
204
205 int cfb_cnattach __P((tc_addr_t));
206 int cfbintr __P((void *));
207 void cfbinit __P((struct fb_devconfig *));
208
209 static int get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
210 static int set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
211 static int set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
212 static int get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
213 static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *));
214 static void bt459_set_curpos __P((struct cfb_softc *));
215
216 /* XXX XXX XXX */
217 #define BT459_SELECT(vdac, regno) do { \
218 vdac->bt_lo = (regno) & 0x00ff; \
219 vdac->bt_hi = ((regno)& 0x0f00) >> 8; \
220 tc_wmb(); \
221 } while (0)
222 /* XXX XXX XXX */
223
224 /*
225 * Compose 2 bit/pixel cursor image. Bit order will be reversed.
226 * M M M M I I I I M I M I M I M I
227 * [ before ] [ after ]
228 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3
229 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7
230 */
231 const static u_int8_t shuffle[256] = {
232 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
233 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
234 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
235 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
236 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
237 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
238 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
239 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
240 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
241 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
242 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
243 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
244 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
245 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
246 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
247 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
248 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
249 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
250 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
251 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
252 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
253 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
254 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
255 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
256 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
257 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
258 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
259 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
260 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
261 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
262 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
263 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
264 };
265
266 int
267 cfbmatch(parent, match, aux)
268 struct device *parent;
269 struct cfdata *match;
270 void *aux;
271 {
272 struct tc_attach_args *ta = aux;
273
274 if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
275 return (0);
276
277 return (1);
278 }
279
280 void
281 cfb_getdevconfig(dense_addr, dc)
282 tc_addr_t dense_addr;
283 struct fb_devconfig *dc;
284 {
285 struct raster *rap;
286 struct rcons *rcp;
287 int i;
288
289 dc->dc_vaddr = dense_addr;
290 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + CX_FB_OFFSET);
291
292 dc->dc_wid = 1024;
293 dc->dc_ht = 864;
294 dc->dc_depth = 8;
295 dc->dc_rowbytes = 1024;
296 dc->dc_videobase = dc->dc_vaddr + CX_FB_OFFSET;
297 dc->dc_blanked = 0;
298
299 /* initialize colormap and cursor resource */
300 cfbinit(dc);
301
302 /* clear the screen */
303 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
304 *(u_int32_t *)(dc->dc_videobase + i) = 0x0;
305
306 /* initialize the raster */
307 rap = &dc->dc_raster;
308 rap->width = dc->dc_wid;
309 rap->height = dc->dc_ht;
310 rap->depth = dc->dc_depth;
311 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
312 rap->pixels = (u_int32_t *)dc->dc_videobase;
313
314 /* initialize the raster console blitter */
315 rcp = &dc->dc_rcons;
316 rcp->rc_sp = rap;
317 rcp->rc_crow = rcp->rc_ccol = -1;
318 rcp->rc_crowp = &rcp->rc_crow;
319 rcp->rc_ccolp = &rcp->rc_ccol;
320 rcons_init(rcp, 34, 80);
321
322 cfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
323 cfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
324 }
325
326 void
327 cfbattach(parent, self, aux)
328 struct device *parent, *self;
329 void *aux;
330 {
331 struct cfb_softc *sc = (struct cfb_softc *)self;
332 struct tc_attach_args *ta = aux;
333 struct wsemuldisplaydev_attach_args waa;
334 struct hwcmap *cm;
335 int console, i;
336
337 console = (ta->ta_addr == cfb_consaddr);
338 if (console) {
339 sc->sc_dc = &cfb_console_dc;
340 sc->nscreens = 1;
341 }
342 else {
343 sc->sc_dc = (struct fb_devconfig *)
344 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
345 cfb_getdevconfig(ta->ta_addr, sc->sc_dc);
346 }
347 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
348 sc->sc_dc->dc_depth);
349
350 cm = &sc->sc_cmap;
351 cm->r[0] = cm->g[0] = cm->b[0] = 0;
352 for (i = 1; i < CMAP_SIZE; i++) {
353 cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
354 }
355 sc->magic_x = CX_MAGIC_X;
356 sc->magic_y = CX_MAGIC_Y;
357
358 /* Establish an interrupt handler, and clear any pending interrupts */
359 tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, cfbintr, sc);
360 *(u_int8_t *)(sc->sc_dc->dc_vaddr + CX_OFFSET_IREQ) = 0;
361
362 waa.console = console;
363 waa.scrdata = &cfb_screenlist;
364 waa.accessops = &cfb_accessops;
365 waa.accesscookie = sc;
366
367 config_found(self, &waa, wsemuldisplaydevprint);
368 }
369
370 int
371 cfbioctl(v, cmd, data, flag, p)
372 void *v;
373 u_long cmd;
374 caddr_t data;
375 int flag;
376 struct proc *p;
377 {
378 struct cfb_softc *sc = v;
379 struct fb_devconfig *dc = sc->sc_dc;
380 int turnoff;
381
382 switch (cmd) {
383 case WSDISPLAYIO_GTYPE:
384 *(u_int *)data = WSDISPLAY_TYPE_CFB;
385 return (0);
386
387 case WSDISPLAYIO_GINFO:
388 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
389 wsd_fbip->height = sc->sc_dc->dc_ht;
390 wsd_fbip->width = sc->sc_dc->dc_wid;
391 wsd_fbip->depth = sc->sc_dc->dc_depth;
392 wsd_fbip->cmsize = CMAP_SIZE;
393 #undef fbt
394 return (0);
395
396 case WSDISPLAYIO_GETCMAP:
397 return get_cmap(sc, (struct wsdisplay_cmap *)data);
398
399 case WSDISPLAYIO_PUTCMAP:
400 return set_cmap(sc, (struct wsdisplay_cmap *)data);
401
402 case WSDISPLAYIO_SVIDEO:
403 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
404 if ((dc->dc_blanked == 0) ^ turnoff) {
405 dc->dc_blanked = turnoff;
406 /* XXX later XXX */
407 }
408 return (0);
409
410 case WSDISPLAYIO_GVIDEO:
411 *(u_int *)data = dc->dc_blanked ?
412 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
413 return (0);
414
415 case WSDISPLAYIO_GCURPOS:
416 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
417 return (0);
418
419 case WSDISPLAYIO_SCURPOS:
420 set_curpos(sc, (struct wsdisplay_curpos *)data);
421 bt459_set_curpos(sc);
422 return (0);
423
424 case WSDISPLAYIO_GCURMAX:
425 ((struct wsdisplay_curpos *)data)->x =
426 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
427 return (0);
428
429 case WSDISPLAYIO_GCURSOR:
430 return get_cursor(sc, (struct wsdisplay_cursor *)data);
431
432 case WSDISPLAYIO_SCURSOR:
433 return set_cursor(sc, (struct wsdisplay_cursor *)data);
434 }
435 return ENOTTY;
436 }
437
438 int
439 cfbmmap(v, offset, prot)
440 void *v;
441 off_t offset;
442 int prot;
443 {
444 struct cfb_softc *sc = v;
445
446 if (offset >= CX_FB_SIZE || offset < 0)
447 return (-1);
448 return machine_btop(sc->sc_dc->dc_paddr + offset);
449 }
450
451 int
452 cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
453 void *v;
454 const struct wsscreen_descr *type;
455 void **cookiep;
456 int *curxp, *curyp;
457 long *attrp;
458 {
459 struct cfb_softc *sc = v;
460 long defattr;
461
462 if (sc->nscreens > 0)
463 return (ENOMEM);
464
465 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
466 *curxp = 0;
467 *curyp = 0;
468 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
469 *attrp = defattr;
470 sc->nscreens++;
471 return (0);
472 }
473
474 void
475 cfb_free_screen(v, cookie)
476 void *v;
477 void *cookie;
478 {
479 struct cfb_softc *sc = v;
480
481 if (sc->sc_dc == &cfb_console_dc)
482 panic("cfb_free_screen: console");
483
484 sc->nscreens--;
485 }
486
487 void
488 cfb_show_screen(v, cookie)
489 void *v;
490 void *cookie;
491 {
492 }
493
494 int
495 cfb_cnattach(addr)
496 tc_addr_t addr;
497 {
498 struct fb_devconfig *dcp = &cfb_console_dc;
499 long defattr;
500
501 cfb_getdevconfig(addr, dcp);
502
503 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
504
505 wsdisplay_cnattach(&cfb_stdscreen, &dcp->dc_rcons,
506 0, 0, defattr);
507 cfb_consaddr = addr;
508 return(0);
509 }
510
511
512 int
513 cfbintr(arg)
514 void *arg;
515 {
516 struct cfb_softc *sc = arg;
517 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
518 struct bt459reg *vdac;
519 int v;
520
521 *(u_int8_t *)(cfbbase + CX_OFFSET_IREQ) = 0;
522 if (sc->sc_changed == 0)
523 return (1);
524
525 vdac = (void *)(cfbbase + CX_BT459_OFFSET);
526 v = sc->sc_changed;
527 sc->sc_changed = 0;
528 if (v & DATA_ENB_CHANGED) {
529 BT459_SELECT(vdac, BT459_REG_CCR);
530 vdac->bt_reg = (sc->sc_curenb) ? 0xc0 : 0x00;
531 }
532 if (v & DATA_CURCMAP_CHANGED) {
533 u_int8_t *cp = sc->sc_cursor.cc_color;
534
535 BT459_SELECT(vdac, BT459_REG_CCOLOR_2);
536 vdac->bt_reg = cp[1]; tc_wmb();
537 vdac->bt_reg = cp[3]; tc_wmb();
538 vdac->bt_reg = cp[5]; tc_wmb();
539
540 vdac->bt_reg = cp[0]; tc_wmb();
541 vdac->bt_reg = cp[2]; tc_wmb();
542 vdac->bt_reg = cp[4]; tc_wmb();
543 }
544 if (v & DATA_CURSHAPE_CHANGED) {
545 u_int8_t *ip, *mp, img, msk;
546 u_int8_t u;
547 int bcnt;
548
549 ip = (u_int8_t *)sc->sc_cursor.cc_image;
550 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
551
552 bcnt = 0;
553 BT459_SELECT(vdac, BT459_REG_CRAM_BASE+0);
554 /* 64 pixel scan line is consisted with 16 byte cursor ram */
555 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
556 /* pad right half 32 pixel when smaller than 33 */
557 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
558 vdac->bt_reg = 0; tc_wmb();
559 vdac->bt_reg = 0; tc_wmb();
560 }
561 else {
562 img = *ip++;
563 msk = *mp++;
564 img &= msk; /* cookie off image */
565 u = (msk & 0x0f) << 4 | (img & 0x0f);
566 vdac->bt_reg = shuffle[u]; tc_wmb();
567 u = (msk & 0xf0) | (img & 0xf0) >> 4;
568 vdac->bt_reg = shuffle[u]; tc_wmb();
569 }
570 bcnt += 2;
571 }
572 /* pad unoccupied scan lines */
573 while (bcnt < CURSOR_MAX_SIZE * 16) {
574 vdac->bt_reg = 0; tc_wmb();
575 vdac->bt_reg = 0; tc_wmb();
576 bcnt += 2;
577 }
578 }
579 if (v & DATA_CMAP_CHANGED) {
580 struct hwcmap *cm = &sc->sc_cmap;
581 int index;
582
583 BT459_SELECT(vdac, 0);
584 for (index = 0; index < CMAP_SIZE; index++) {
585 vdac->bt_cmap = cm->r[index]; tc_wmb();
586 vdac->bt_cmap = cm->g[index]; tc_wmb();
587 vdac->bt_cmap = cm->b[index]; tc_wmb();
588 }
589 }
590 return (1);
591 }
592
593 void
594 cfbinit(dc)
595 struct fb_devconfig *dc;
596 {
597 caddr_t cfbbase = (caddr_t)dc->dc_vaddr;
598 struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET);
599 int i;
600
601 BT459_SELECT(vdac, BT459_REG_COMMAND_0);
602 vdac->bt_reg = 0x40; /* CMD0 */ tc_wmb();
603 vdac->bt_reg = 0x0; /* CMD1 */ tc_wmb();
604 vdac->bt_reg = 0xc0; /* CMD2 */ tc_wmb();
605 vdac->bt_reg = 0xff; /* PRM */ tc_wmb();
606 vdac->bt_reg = 0; /* 205 */ tc_wmb();
607 vdac->bt_reg = 0x0; /* PBM */ tc_wmb();
608 vdac->bt_reg = 0; /* 207 */ tc_wmb();
609 vdac->bt_reg = 0x0; /* ORM */ tc_wmb();
610 vdac->bt_reg = 0x0; /* OBM */ tc_wmb();
611 vdac->bt_reg = 0x0; /* ILV */ tc_wmb();
612 vdac->bt_reg = 0x0; /* TEST */ tc_wmb();
613
614 BT459_SELECT(vdac, BT459_REG_CCR);
615 vdac->bt_reg = 0x0; tc_wmb();
616 vdac->bt_reg = 0x0; tc_wmb();
617 vdac->bt_reg = 0x0; tc_wmb();
618 vdac->bt_reg = 0x0; tc_wmb();
619 vdac->bt_reg = 0x0; tc_wmb();
620 vdac->bt_reg = 0x0; tc_wmb();
621 vdac->bt_reg = 0x0; tc_wmb();
622 vdac->bt_reg = 0x0; tc_wmb();
623 vdac->bt_reg = 0x0; tc_wmb();
624 vdac->bt_reg = 0x0; tc_wmb();
625 vdac->bt_reg = 0x0; tc_wmb();
626 vdac->bt_reg = 0x0; tc_wmb();
627 vdac->bt_reg = 0x0; tc_wmb();
628
629 /* build sane colormap */
630 BT459_SELECT(vdac, 0);
631 vdac->bt_cmap = 0; tc_wmb();
632 vdac->bt_cmap = 0; tc_wmb();
633 vdac->bt_cmap = 0; tc_wmb();
634 for (i = 1; i < CMAP_SIZE; i++) {
635 vdac->bt_cmap = 0xff; tc_wmb();
636 vdac->bt_cmap = 0xff; tc_wmb();
637 vdac->bt_cmap = 0xff; tc_wmb();
638 }
639
640 /* clear out cursor image */
641 BT459_SELECT(vdac, BT459_REG_CRAM_BASE);
642 for (i = 0; i < 1024; i++)
643 vdac->bt_reg = 0xff; tc_wmb();
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 BT459_SELECT(vdac, BT459_REG_CCOLOR_1);
651 vdac->bt_reg = 0xff; tc_wmb();
652 vdac->bt_reg = 0xff; tc_wmb();
653 vdac->bt_reg = 0xff; tc_wmb();
654
655 vdac->bt_reg = 0; tc_wmb();
656 vdac->bt_reg = 0; tc_wmb();
657 vdac->bt_reg = 0; tc_wmb();
658
659 vdac->bt_reg = 0xff; tc_wmb();
660 vdac->bt_reg = 0xff; tc_wmb();
661 vdac->bt_reg = 0xff; tc_wmb();
662 }
663
664 static int
665 get_cmap(sc, p)
666 struct cfb_softc *sc;
667 struct wsdisplay_cmap *p;
668 {
669 u_int index = p->index, count = p->count;
670
671 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
672 return (EINVAL);
673
674 if (!uvm_useracc(p->red, count, B_WRITE) ||
675 !uvm_useracc(p->green, count, B_WRITE) ||
676 !uvm_useracc(p->blue, count, B_WRITE))
677 return (EFAULT);
678
679 copyout(&sc->sc_cmap.r[index], p->red, count);
680 copyout(&sc->sc_cmap.g[index], p->green, count);
681 copyout(&sc->sc_cmap.b[index], p->blue, count);
682
683 return (0);
684 }
685
686 static int
687 set_cmap(sc, p)
688 struct cfb_softc *sc;
689 struct wsdisplay_cmap *p;
690 {
691 u_int index = p->index, count = p->count;
692
693 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
694 return (EINVAL);
695
696 if (!uvm_useracc(p->red, count, B_READ) ||
697 !uvm_useracc(p->green, count, B_READ) ||
698 !uvm_useracc(p->blue, count, B_READ))
699 return (EFAULT);
700
701 copyin(p->red, &sc->sc_cmap.r[index], count);
702 copyin(p->green, &sc->sc_cmap.g[index], count);
703 copyin(p->blue, &sc->sc_cmap.b[index], count);
704
705 sc->sc_changed |= DATA_CMAP_CHANGED;
706
707 return (0);
708 }
709
710 static int
711 set_cursor(sc, p)
712 struct cfb_softc *sc;
713 struct wsdisplay_cursor *p;
714 {
715 #define cc (&sc->sc_cursor)
716 int v, index, count, icount;
717
718 v = p->which;
719 if (v & WSDISPLAY_CURSOR_DOCMAP) {
720 index = p->cmap.index;
721 count = p->cmap.count;
722 if (index >= 2 || (index + count) > 2)
723 return (EINVAL);
724 if (!uvm_useracc(p->cmap.red, count, B_READ) ||
725 !uvm_useracc(p->cmap.green, count, B_READ) ||
726 !uvm_useracc(p->cmap.blue, count, B_READ))
727 return (EFAULT);
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 if (!uvm_useracc(p->image, icount, B_READ) ||
734 !uvm_useracc(p->mask, icount, B_READ))
735 return (EFAULT);
736 }
737 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
738 if (v & WSDISPLAY_CURSOR_DOCUR)
739 cc->cc_hot = p->hot;
740 if (v & WSDISPLAY_CURSOR_DOPOS)
741 set_curpos(sc, &p->pos);
742 bt459_set_curpos(sc);
743 }
744
745 sc->sc_changed = 0;
746 if (v & WSDISPLAY_CURSOR_DOCUR) {
747 sc->sc_curenb = p->enable;
748 sc->sc_changed |= DATA_ENB_CHANGED;
749 }
750 if (v & WSDISPLAY_CURSOR_DOCMAP) {
751 copyin(p->cmap.red, &cc->cc_color[index], count);
752 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
753 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
754 sc->sc_changed |= DATA_CURCMAP_CHANGED;
755 }
756 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
757 cc->cc_size = p->size;
758 memset(cc->cc_image, 0, sizeof cc->cc_image);
759 copyin(p->image, cc->cc_image, icount);
760 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
761 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
762 }
763
764 return (0);
765 #undef cc
766 }
767
768 static int
769 get_cursor(sc, p)
770 struct cfb_softc *sc;
771 struct wsdisplay_cursor *p;
772 {
773 return (ENOTTY); /* XXX */
774 }
775
776 static void
777 set_curpos(sc, curpos)
778 struct cfb_softc *sc;
779 struct wsdisplay_curpos *curpos;
780 {
781 struct fb_devconfig *dc = sc->sc_dc;
782 int x = curpos->x, y = curpos->y;
783
784 if (y < 0)
785 y = 0;
786 else if (y > dc->dc_ht)
787 y = dc->dc_ht;
788 if (x < 0)
789 x = 0;
790 else if (x > dc->dc_wid)
791 x = dc->dc_wid;
792 sc->sc_cursor.cc_pos.x = x;
793 sc->sc_cursor.cc_pos.y = y;
794 }
795
796 void
797 bt459_set_curpos(sc)
798 struct cfb_softc *sc;
799 {
800 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
801 struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET);
802 int x, y, s;
803
804 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
805 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
806 x += sc->magic_x; y += sc->magic_y; /* magic offset of CX coordinate */
807
808 s = spltty();
809
810 BT459_SELECT(vdac, BT459_REG_CURSOR_X_LOW);
811 vdac->bt_reg = x; tc_wmb();
812 vdac->bt_reg = x >> 8; tc_wmb();
813 vdac->bt_reg = y; tc_wmb();
814 vdac->bt_reg = y >> 8; tc_wmb();
815
816 splx(s);
817 }
818