cfb.c revision 1.15 1 /* $NetBSD: cfb.c,v 1.15 1999/12/06 19:26:00 drochner 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.15 1999/12/06 19:26:00 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
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 static int cfbmatch __P((struct device *, struct cfdata *, void *));
163 static void cfbattach __P((struct device *, struct device *, void *));
164
165 const struct cfattach cfb_ca = {
166 sizeof(struct cfb_softc), cfbmatch, cfbattach,
167 };
168
169 static void cfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
170 static struct fb_devconfig cfb_console_dc;
171 static tc_addr_t cfb_consaddr;
172
173 static const 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 static struct wsscreen_descr cfb_stdscreen = {
185 "std", 0, 0,
186 &cfb_emulops,
187 0, 0,
188 WSSCREEN_REVERSE
189 };
190
191 static const struct wsscreen_descr *_cfb_scrlist[] = {
192 &cfb_stdscreen,
193 };
194
195 static const struct wsscreen_list cfb_screenlist = {
196 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
197 };
198
199 static int cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
200 static int cfbmmap __P((void *, off_t, int));
201
202 static int cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
203 void **, int *, int *, long *));
204 static void cfb_free_screen __P((void *, void *));
205 static int cfb_show_screen __P((void *, void *, int,
206 void (*) (void *, int, int), void *));
207
208 static const struct wsdisplay_accessops cfb_accessops = {
209 cfbioctl,
210 cfbmmap,
211 cfb_alloc_screen,
212 cfb_free_screen,
213 cfb_show_screen,
214 0 /* load_font */
215 };
216
217 int cfb_cnattach __P((tc_addr_t));
218 static int cfbintr __P((void *));
219 static void cfbinit __P((struct fb_devconfig *));
220
221 static int get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
222 static int set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
223 static int set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
224 static int get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
225 static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *));
226 static void bt459_set_curpos __P((struct cfb_softc *));
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 static const 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 static 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 static 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 static 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 hwcmap256 *cm;
339 int console;
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 memset(cm, 255, sizeof(struct hwcmap256)); /* XXX */
356 cm->r[0] = cm->g[0] = cm->b[0] = 0; /* XXX */
357
358 sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
359 sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
360
361 /* Establish an interrupt handler, and clear any pending interrupts */
362 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
363 *(u_int8_t *)(sc->sc_dc->dc_vaddr + CX_OFFSET_IREQ) = 0;
364
365 waa.console = console;
366 waa.scrdata = &cfb_screenlist;
367 waa.accessops = &cfb_accessops;
368 waa.accesscookie = sc;
369
370 config_found(self, &waa, wsemuldisplaydevprint);
371 }
372
373 static int
374 cfbioctl(v, cmd, data, flag, p)
375 void *v;
376 u_long cmd;
377 caddr_t data;
378 int flag;
379 struct proc *p;
380 {
381 struct cfb_softc *sc = v;
382 struct fb_devconfig *dc = sc->sc_dc;
383 int turnoff;
384
385 switch (cmd) {
386 case WSDISPLAYIO_GTYPE:
387 *(u_int *)data = WSDISPLAY_TYPE_CFB;
388 return (0);
389
390 case WSDISPLAYIO_GINFO:
391 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
392 wsd_fbip->height = sc->sc_dc->dc_ht;
393 wsd_fbip->width = sc->sc_dc->dc_wid;
394 wsd_fbip->depth = sc->sc_dc->dc_depth;
395 wsd_fbip->cmsize = CMAP_SIZE;
396 #undef fbt
397 return (0);
398
399 case WSDISPLAYIO_GETCMAP:
400 return get_cmap(sc, (struct wsdisplay_cmap *)data);
401
402 case WSDISPLAYIO_PUTCMAP:
403 return set_cmap(sc, (struct wsdisplay_cmap *)data);
404
405 case WSDISPLAYIO_SVIDEO:
406 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
407 if ((dc->dc_blanked == 0) ^ turnoff) {
408 dc->dc_blanked = turnoff;
409 /* XXX later XXX */
410 }
411 return (0);
412
413 case WSDISPLAYIO_GVIDEO:
414 *(u_int *)data = dc->dc_blanked ?
415 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
416 return (0);
417
418 case WSDISPLAYIO_GCURPOS:
419 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
420 return (0);
421
422 case WSDISPLAYIO_SCURPOS:
423 set_curpos(sc, (struct wsdisplay_curpos *)data);
424 bt459_set_curpos(sc);
425 return (0);
426
427 case WSDISPLAYIO_GCURMAX:
428 ((struct wsdisplay_curpos *)data)->x =
429 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
430 return (0);
431
432 case WSDISPLAYIO_GCURSOR:
433 return get_cursor(sc, (struct wsdisplay_cursor *)data);
434
435 case WSDISPLAYIO_SCURSOR:
436 return set_cursor(sc, (struct wsdisplay_cursor *)data);
437 }
438 return ENOTTY;
439 }
440
441 int
442 cfbmmap(v, offset, prot)
443 void *v;
444 off_t offset;
445 int prot;
446 {
447 struct cfb_softc *sc = v;
448
449 if (offset >= CX_FB_SIZE || offset < 0)
450 return (-1);
451 return machine_btop(sc->sc_dc->dc_paddr + offset);
452 }
453
454 static int
455 cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
456 void *v;
457 const struct wsscreen_descr *type;
458 void **cookiep;
459 int *curxp, *curyp;
460 long *attrp;
461 {
462 struct cfb_softc *sc = v;
463 long defattr;
464
465 if (sc->nscreens > 0)
466 return (ENOMEM);
467
468 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
469 *curxp = 0;
470 *curyp = 0;
471 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
472 *attrp = defattr;
473 sc->nscreens++;
474 return (0);
475 }
476
477 static void
478 cfb_free_screen(v, cookie)
479 void *v;
480 void *cookie;
481 {
482 struct cfb_softc *sc = v;
483
484 if (sc->sc_dc == &cfb_console_dc)
485 panic("cfb_free_screen: console");
486
487 sc->nscreens--;
488 }
489
490 static int
491 cfb_show_screen(v, cookie)
492 void *v;
493 void *cookie;
494 int waitok;
495 void (*cb) __P((void *, int, int));
496 void *cbarg;
497 {
498
499 return (0);
500 }
501
502 /* EXPORT */ int
503 cfb_cnattach(addr)
504 tc_addr_t addr;
505 {
506 struct fb_devconfig *dcp = &cfb_console_dc;
507 long defattr;
508
509 cfb_getdevconfig(addr, dcp);
510
511 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
512
513 wsdisplay_cnattach(&cfb_stdscreen, &dcp->dc_rcons,
514 0, 0, defattr);
515 cfb_consaddr = addr;
516 return(0);
517 }
518
519
520 static int
521 cfbintr(arg)
522 void *arg;
523 {
524 struct cfb_softc *sc = arg;
525 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
526 struct bt459reg *vdac;
527 int v;
528
529 *(u_int8_t *)(cfbbase + CX_OFFSET_IREQ) = 0;
530 if (sc->sc_changed == 0)
531 return (1);
532
533 vdac = (void *)(cfbbase + CX_BT459_OFFSET);
534 v = sc->sc_changed;
535 sc->sc_changed = 0;
536 if (v & DATA_ENB_CHANGED) {
537 SELECT(vdac, BT459_REG_CCR);
538 REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
539 }
540 if (v & DATA_CURCMAP_CHANGED) {
541 u_int8_t *cp = sc->sc_cursor.cc_color;
542
543 SELECT(vdac, BT459_REG_CCOLOR_2);
544 REG(vdac, bt_reg) = cp[1]; tc_wmb();
545 REG(vdac, bt_reg) = cp[3]; tc_wmb();
546 REG(vdac, bt_reg) = cp[5]; tc_wmb();
547
548 REG(vdac, bt_reg) = cp[0]; tc_wmb();
549 REG(vdac, bt_reg) = cp[2]; tc_wmb();
550 REG(vdac, bt_reg) = cp[4]; tc_wmb();
551 }
552 if (v & DATA_CURSHAPE_CHANGED) {
553 u_int8_t *ip, *mp, img, msk;
554 u_int8_t u;
555 int bcnt;
556
557 ip = (u_int8_t *)sc->sc_cursor.cc_image;
558 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
559
560 bcnt = 0;
561 SELECT(vdac, BT459_REG_CRAM_BASE+0);
562 /* 64 pixel scan line is consisted with 16 byte cursor ram */
563 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
564 /* pad right half 32 pixel when smaller than 33 */
565 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
566 REG(vdac, bt_reg) = 0; tc_wmb();
567 REG(vdac, bt_reg) = 0; tc_wmb();
568 }
569 else {
570 img = *ip++;
571 msk = *mp++;
572 img &= msk; /* cookie off image */
573 u = (msk & 0x0f) << 4 | (img & 0x0f);
574 REG(vdac, bt_reg) = shuffle[u]; tc_wmb();
575 u = (msk & 0xf0) | (img & 0xf0) >> 4;
576 REG(vdac, bt_reg) = shuffle[u]; tc_wmb();
577 }
578 bcnt += 2;
579 }
580 /* pad unoccupied scan lines */
581 while (bcnt < CURSOR_MAX_SIZE * 16) {
582 REG(vdac, bt_reg) = 0; tc_wmb();
583 REG(vdac, bt_reg) = 0; tc_wmb();
584 bcnt += 2;
585 }
586 }
587 if (v & DATA_CMAP_CHANGED) {
588 struct hwcmap256 *cm = &sc->sc_cmap;
589 int index;
590
591 SELECT(vdac, 0);
592 for (index = 0; index < CMAP_SIZE; index++) {
593 REG(vdac, bt_cmap) = cm->r[index]; tc_wmb();
594 REG(vdac, bt_cmap) = cm->g[index]; tc_wmb();
595 REG(vdac, bt_cmap) = cm->b[index]; tc_wmb();
596 }
597 }
598 return (1);
599 }
600
601 static void
602 cfbinit(dc)
603 struct fb_devconfig *dc;
604 {
605 caddr_t cfbbase = (caddr_t)dc->dc_vaddr;
606 struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET);
607 int i;
608
609 SELECT(vdac, BT459_REG_COMMAND_0);
610 REG(vdac, bt_reg) = 0x40; /* CMD0 */ tc_wmb();
611 REG(vdac, bt_reg) = 0x0; /* CMD1 */ tc_wmb();
612 REG(vdac, bt_reg) = 0xc0; /* CMD2 */ tc_wmb();
613 REG(vdac, bt_reg) = 0xff; /* PRM */ tc_wmb();
614 REG(vdac, bt_reg) = 0; /* 205 */ tc_wmb();
615 REG(vdac, bt_reg) = 0x0; /* PBM */ tc_wmb();
616 REG(vdac, bt_reg) = 0; /* 207 */ tc_wmb();
617 REG(vdac, bt_reg) = 0x0; /* ORM */ tc_wmb();
618 REG(vdac, bt_reg) = 0x0; /* OBM */ tc_wmb();
619 REG(vdac, bt_reg) = 0x0; /* ILV */ tc_wmb();
620 REG(vdac, bt_reg) = 0x0; /* TEST */ tc_wmb();
621
622 SELECT(vdac, BT459_REG_CCR);
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 REG(vdac, bt_reg) = 0x0; tc_wmb();
631 REG(vdac, bt_reg) = 0x0; tc_wmb();
632 REG(vdac, bt_reg) = 0x0; tc_wmb();
633 REG(vdac, bt_reg) = 0x0; tc_wmb();
634 REG(vdac, bt_reg) = 0x0; tc_wmb();
635 REG(vdac, bt_reg) = 0x0; tc_wmb();
636
637 /* build sane colormap */
638 SELECT(vdac, 0);
639 REG(vdac, bt_cmap) = 0; tc_wmb();
640 REG(vdac, bt_cmap) = 0; tc_wmb();
641 REG(vdac, bt_cmap) = 0; tc_wmb();
642 for (i = 1; i < CMAP_SIZE; i++) {
643 REG(vdac, bt_cmap) = 0xff; tc_wmb();
644 REG(vdac, bt_cmap) = 0xff; tc_wmb();
645 REG(vdac, bt_cmap) = 0xff; tc_wmb();
646 }
647
648 /* clear out cursor image */
649 SELECT(vdac, BT459_REG_CRAM_BASE);
650 for (i = 0; i < 1024; i++)
651 REG(vdac, bt_reg) = 0xff; tc_wmb();
652
653 /*
654 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
655 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for
656 * image color. CCOLOR_1 will be never used.
657 */
658 SELECT(vdac, BT459_REG_CCOLOR_1);
659 REG(vdac, bt_reg) = 0xff; tc_wmb();
660 REG(vdac, bt_reg) = 0xff; tc_wmb();
661 REG(vdac, bt_reg) = 0xff; tc_wmb();
662
663 REG(vdac, bt_reg) = 0; tc_wmb();
664 REG(vdac, bt_reg) = 0; tc_wmb();
665 REG(vdac, bt_reg) = 0; tc_wmb();
666
667 REG(vdac, bt_reg) = 0xff; tc_wmb();
668 REG(vdac, bt_reg) = 0xff; tc_wmb();
669 REG(vdac, bt_reg) = 0xff; tc_wmb();
670 }
671
672 static int
673 get_cmap(sc, p)
674 struct cfb_softc *sc;
675 struct wsdisplay_cmap *p;
676 {
677 u_int index = p->index, count = p->count;
678
679 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
680 return (EINVAL);
681
682 if (!uvm_useracc(p->red, count, B_WRITE) ||
683 !uvm_useracc(p->green, count, B_WRITE) ||
684 !uvm_useracc(p->blue, count, B_WRITE))
685 return (EFAULT);
686
687 copyout(&sc->sc_cmap.r[index], p->red, count);
688 copyout(&sc->sc_cmap.g[index], p->green, count);
689 copyout(&sc->sc_cmap.b[index], p->blue, count);
690
691 return (0);
692 }
693
694 static int
695 set_cmap(sc, p)
696 struct cfb_softc *sc;
697 struct wsdisplay_cmap *p;
698 {
699 u_int index = p->index, count = p->count;
700
701 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
702 return (EINVAL);
703
704 if (!uvm_useracc(p->red, count, B_READ) ||
705 !uvm_useracc(p->green, count, B_READ) ||
706 !uvm_useracc(p->blue, count, B_READ))
707 return (EFAULT);
708
709 copyin(p->red, &sc->sc_cmap.r[index], count);
710 copyin(p->green, &sc->sc_cmap.g[index], count);
711 copyin(p->blue, &sc->sc_cmap.b[index], count);
712
713 sc->sc_changed |= DATA_CMAP_CHANGED;
714
715 return (0);
716 }
717
718 static int
719 set_cursor(sc, p)
720 struct cfb_softc *sc;
721 struct wsdisplay_cursor *p;
722 {
723 #define cc (&sc->sc_cursor)
724 int v, index, count, icount;
725
726 v = p->which;
727 if (v & WSDISPLAY_CURSOR_DOCMAP) {
728 index = p->cmap.index;
729 count = p->cmap.count;
730 if (index >= 2 || (index + count) > 2)
731 return (EINVAL);
732 if (!uvm_useracc(p->cmap.red, count, B_READ) ||
733 !uvm_useracc(p->cmap.green, count, B_READ) ||
734 !uvm_useracc(p->cmap.blue, count, B_READ))
735 return (EFAULT);
736 }
737 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
738 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
739 return (EINVAL);
740 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
741 if (!uvm_useracc(p->image, icount, B_READ) ||
742 !uvm_useracc(p->mask, icount, B_READ))
743 return (EFAULT);
744 }
745 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
746 if (v & WSDISPLAY_CURSOR_DOCUR)
747 cc->cc_hot = p->hot;
748 if (v & WSDISPLAY_CURSOR_DOPOS)
749 set_curpos(sc, &p->pos);
750 bt459_set_curpos(sc);
751 }
752
753 sc->sc_changed = 0;
754 if (v & WSDISPLAY_CURSOR_DOCUR) {
755 sc->sc_curenb = p->enable;
756 sc->sc_changed |= DATA_ENB_CHANGED;
757 }
758 if (v & WSDISPLAY_CURSOR_DOCMAP) {
759 copyin(p->cmap.red, &cc->cc_color[index], count);
760 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
761 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
762 sc->sc_changed |= DATA_CURCMAP_CHANGED;
763 }
764 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
765 cc->cc_size = p->size;
766 memset(cc->cc_image, 0, sizeof cc->cc_image);
767 copyin(p->image, cc->cc_image, icount);
768 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
769 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
770 }
771
772 return (0);
773 #undef cc
774 }
775
776 static int
777 get_cursor(sc, p)
778 struct cfb_softc *sc;
779 struct wsdisplay_cursor *p;
780 {
781 return (ENOTTY); /* XXX */
782 }
783
784 static void
785 set_curpos(sc, curpos)
786 struct cfb_softc *sc;
787 struct wsdisplay_curpos *curpos;
788 {
789 struct fb_devconfig *dc = sc->sc_dc;
790 int x = curpos->x, y = curpos->y;
791
792 if (y < 0)
793 y = 0;
794 else if (y > dc->dc_ht)
795 y = dc->dc_ht;
796 if (x < 0)
797 x = 0;
798 else if (x > dc->dc_wid)
799 x = dc->dc_wid;
800 sc->sc_cursor.cc_pos.x = x;
801 sc->sc_cursor.cc_pos.y = y;
802 }
803
804 void
805 bt459_set_curpos(sc)
806 struct cfb_softc *sc;
807 {
808 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
809 struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET);
810 int x, y, s;
811
812 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
813 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
814
815 x += sc->sc_cursor.cc_magic.x;
816 y += sc->sc_cursor.cc_magic.y;
817
818 s = spltty();
819
820 SELECT(vdac, BT459_REG_CURSOR_X_LOW);
821 REG(vdac, bt_reg) = x; tc_wmb();
822 REG(vdac, bt_reg) = x >> 8; tc_wmb();
823 REG(vdac, bt_reg) = y; tc_wmb();
824 REG(vdac, bt_reg) = y >> 8; tc_wmb();
825
826 splx(s);
827 }
828