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