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