cfb.c revision 1.23 1 /* $NetBSD: cfb.c,v 1.23 2000/09/13 02:11:14 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.23 2000/09/13 02:11:14 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
45 #include <machine/bus.h>
46 #include <machine/intr.h>
47
48 #include <dev/wscons/wsconsio.h>
49 #include <dev/wscons/wsdisplayvar.h>
50
51 #include <dev/rasops/rasops.h>
52 #include <dev/wsfont/wsfont.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 int dc_blanked; /* currently has video disabled */
118
119 struct rasops_info rinfo;
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 struct wsscreen_descr cfb_stdscreen = {
174 "std", 0, 0,
175 0, /* textops */
176 0, 0,
177 WSSCREEN_REVERSE
178 };
179
180 static const struct wsscreen_descr *_cfb_scrlist[] = {
181 &cfb_stdscreen,
182 };
183
184 static const struct wsscreen_list cfb_screenlist = {
185 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
186 };
187
188 static int cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
189 static paddr_t cfbmmap __P((void *, off_t, int));
190
191 static int cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
192 void **, int *, int *, long *));
193 static void cfb_free_screen __P((void *, void *));
194 static int cfb_show_screen __P((void *, void *, int,
195 void (*) (void *, int, int), void *));
196
197 static const struct wsdisplay_accessops cfb_accessops = {
198 cfbioctl,
199 cfbmmap,
200 cfb_alloc_screen,
201 cfb_free_screen,
202 cfb_show_screen,
203 0 /* load_font */
204 };
205
206 int cfb_cnattach __P((tc_addr_t));
207 static int cfbintr __P((void *));
208 static void cfbinit __P((struct fb_devconfig *));
209
210 static int get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
211 static int set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
212 static int set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
213 static int get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
214 static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *));
215 static void bt459_set_curpos __P((struct cfb_softc *));
216
217 /*
218 * Compose 2 bit/pixel cursor image. Bit order will be reversed.
219 * M M M M I I I I M I M I M I M I
220 * [ before ] [ after ]
221 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3
222 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7
223 */
224 static const u_int8_t shuffle[256] = {
225 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
226 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
227 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
228 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
229 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
230 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
231 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
232 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
233 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
234 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
235 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
236 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
237 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
238 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
239 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
240 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
241 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
242 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
243 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
244 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
245 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
246 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
247 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
248 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
249 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
250 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
251 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
252 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
253 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
254 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
255 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
256 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
257 };
258
259 static int
260 cfbmatch(parent, match, aux)
261 struct device *parent;
262 struct cfdata *match;
263 void *aux;
264 {
265 struct tc_attach_args *ta = aux;
266
267 if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
268 return (0);
269
270 return (1);
271 }
272
273 static void
274 cfb_getdevconfig(dense_addr, dc)
275 tc_addr_t dense_addr;
276 struct fb_devconfig *dc;
277 {
278 int i, cookie;
279
280 dc->dc_vaddr = dense_addr;
281 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + CX_FB_OFFSET);
282
283 dc->dc_wid = 1024;
284 dc->dc_ht = 864;
285 dc->dc_depth = 8;
286 dc->dc_rowbytes = 1024;
287 dc->dc_videobase = dc->dc_vaddr + CX_FB_OFFSET;
288 dc->dc_blanked = 0;
289
290 /* initialize colormap and cursor resource */
291 cfbinit(dc);
292
293 /* clear the screen */
294 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
295 *(u_int32_t *)(dc->dc_videobase + i) = 0x0;
296
297 dc->rinfo.ri_flg = RI_CENTER;
298 dc->rinfo.ri_depth = dc->dc_depth;
299 dc->rinfo.ri_bits = (void *)dc->dc_videobase;
300 dc->rinfo.ri_width = dc->dc_wid;
301 dc->rinfo.ri_height = dc->dc_ht;
302 dc->rinfo.ri_stride = dc->dc_rowbytes;
303
304 wsfont_init();
305 /* prefer 8 pixel wide font */
306 if ((cookie = wsfont_find(NULL, 8, 0, 0)) <= 0)
307 cookie = wsfont_find(NULL, 0, 0, 0);
308 if (cookie <= 0) {
309 printf("cfb: font table is empty\n");
310 return;
311 }
312
313 if (wsfont_lock(cookie, &dc->rinfo.ri_font,
314 WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
315 printf("cfb: couldn't lock font\n");
316 return;
317 }
318 dc->rinfo.ri_wsfcookie = cookie;
319
320 rasops_init(&dc->rinfo, 34, 80);
321
322 /* XXX shouldn't be global */
323 cfb_stdscreen.nrows = dc->rinfo.ri_rows;
324 cfb_stdscreen.ncols = dc->rinfo.ri_cols;
325 cfb_stdscreen.textops = &dc->rinfo.ri_ops;
326 cfb_stdscreen.capabilities = dc->rinfo.ri_caps;
327 }
328
329 static 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 int console;
338
339 console = (ta->ta_addr == cfb_consaddr);
340 if (console) {
341 sc->sc_dc = &cfb_console_dc;
342 sc->nscreens = 1;
343 }
344 else {
345 sc->sc_dc = (struct fb_devconfig *)
346 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
347 cfb_getdevconfig(ta->ta_addr, sc->sc_dc);
348 }
349 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
350 sc->sc_dc->dc_depth);
351
352 memcpy(&sc->sc_cmap, rasops_cmap, sizeof(struct hwcmap256));
353
354 sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
355 sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
356
357 /* Establish an interrupt handler, and clear any pending interrupts */
358 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
359 *(u_int8_t *)(sc->sc_dc->dc_vaddr + CX_OFFSET_IREQ) = 0;
360
361 waa.console = console;
362 waa.scrdata = &cfb_screenlist;
363 waa.accessops = &cfb_accessops;
364 waa.accesscookie = sc;
365
366 config_found(self, &waa, wsemuldisplaydevprint);
367 }
368
369 static int
370 cfbioctl(v, cmd, data, flag, p)
371 void *v;
372 u_long cmd;
373 caddr_t data;
374 int flag;
375 struct proc *p;
376 {
377 struct cfb_softc *sc = v;
378 struct fb_devconfig *dc = sc->sc_dc;
379 int turnoff;
380
381 switch (cmd) {
382 case WSDISPLAYIO_GTYPE:
383 *(u_int *)data = WSDISPLAY_TYPE_CFB;
384 return (0);
385
386 case WSDISPLAYIO_GINFO:
387 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
388 wsd_fbip->height = sc->sc_dc->dc_ht;
389 wsd_fbip->width = sc->sc_dc->dc_wid;
390 wsd_fbip->depth = sc->sc_dc->dc_depth;
391 wsd_fbip->cmsize = CMAP_SIZE;
392 #undef fbt
393 return (0);
394
395 case WSDISPLAYIO_GETCMAP:
396 return get_cmap(sc, (struct wsdisplay_cmap *)data);
397
398 case WSDISPLAYIO_PUTCMAP:
399 return set_cmap(sc, (struct wsdisplay_cmap *)data);
400
401 case WSDISPLAYIO_SVIDEO:
402 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
403 if ((dc->dc_blanked == 0) ^ turnoff) {
404 dc->dc_blanked = turnoff;
405 /* XXX later XXX */
406 }
407 return (0);
408
409 case WSDISPLAYIO_GVIDEO:
410 *(u_int *)data = dc->dc_blanked ?
411 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
412 return (0);
413
414 case WSDISPLAYIO_GCURPOS:
415 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
416 return (0);
417
418 case WSDISPLAYIO_SCURPOS:
419 set_curpos(sc, (struct wsdisplay_curpos *)data);
420 bt459_set_curpos(sc);
421 return (0);
422
423 case WSDISPLAYIO_GCURMAX:
424 ((struct wsdisplay_curpos *)data)->x =
425 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
426 return (0);
427
428 case WSDISPLAYIO_GCURSOR:
429 return get_cursor(sc, (struct wsdisplay_cursor *)data);
430
431 case WSDISPLAYIO_SCURSOR:
432 return set_cursor(sc, (struct wsdisplay_cursor *)data);
433 }
434 return ENOTTY;
435 }
436
437 paddr_t
438 cfbmmap(v, offset, prot)
439 void *v;
440 off_t offset;
441 int prot;
442 {
443 struct cfb_softc *sc = v;
444
445 if (offset >= CX_FB_SIZE || offset < 0)
446 return (-1);
447 return machine_btop(sc->sc_dc->dc_paddr + offset);
448 }
449
450 static int
451 cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
452 void *v;
453 const struct wsscreen_descr *type;
454 void **cookiep;
455 int *curxp, *curyp;
456 long *attrp;
457 {
458 struct cfb_softc *sc = v;
459 long defattr;
460
461 if (sc->nscreens > 0)
462 return (ENOMEM);
463
464 *cookiep = &sc->sc_dc->rinfo; /* one and only for now */
465 *curxp = 0;
466 *curyp = 0;
467 (*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr);
468 *attrp = defattr;
469 sc->nscreens++;
470 return (0);
471 }
472
473 static void
474 cfb_free_screen(v, cookie)
475 void *v;
476 void *cookie;
477 {
478 struct cfb_softc *sc = v;
479
480 if (sc->sc_dc == &cfb_console_dc)
481 panic("cfb_free_screen: console");
482
483 sc->nscreens--;
484 }
485
486 static int
487 cfb_show_screen(v, cookie, waitok, cb, cbarg)
488 void *v;
489 void *cookie;
490 int waitok;
491 void (*cb) __P((void *, int, int));
492 void *cbarg;
493 {
494
495 return (0);
496 }
497
498 /* EXPORT */ 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 (*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr);
507 wsdisplay_cnattach(&cfb_stdscreen, &dcp->rinfo, 0, 0, defattr);
508 cfb_consaddr = addr;
509 return(0);
510 }
511
512 static 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 SELECT(vdac, BT459_IREG_CCR);
530 REG(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 SELECT(vdac, BT459_IREG_CCOLOR_2);
536 REG(vdac, bt_reg) = cp[1]; tc_wmb();
537 REG(vdac, bt_reg) = cp[3]; tc_wmb();
538 REG(vdac, bt_reg) = cp[5]; tc_wmb();
539
540 REG(vdac, bt_reg) = cp[0]; tc_wmb();
541 REG(vdac, bt_reg) = cp[2]; tc_wmb();
542 REG(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 SELECT(vdac, BT459_IREG_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 REG(vdac, bt_reg) = 0; tc_wmb();
559 REG(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 REG(vdac, bt_reg) = shuffle[u]; tc_wmb();
567 u = (msk & 0xf0) | (img & 0xf0) >> 4;
568 REG(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 REG(vdac, bt_reg) = 0; tc_wmb();
575 REG(vdac, bt_reg) = 0; tc_wmb();
576 bcnt += 2;
577 }
578 }
579 if (v & DATA_CMAP_CHANGED) {
580 struct hwcmap256 *cm = &sc->sc_cmap;
581 int index;
582
583 SELECT(vdac, 0);
584 for (index = 0; index < CMAP_SIZE; index++) {
585 REG(vdac, bt_cmap) = cm->r[index]; tc_wmb();
586 REG(vdac, bt_cmap) = cm->g[index]; tc_wmb();
587 REG(vdac, bt_cmap) = cm->b[index]; tc_wmb();
588 }
589 }
590 return (1);
591 }
592
593 static 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 SELECT(vdac, BT459_IREG_COMMAND_0);
602 REG(vdac, bt_reg) = 0x40; /* CMD0 */ tc_wmb();
603 REG(vdac, bt_reg) = 0x0; /* CMD1 */ tc_wmb();
604 REG(vdac, bt_reg) = 0xc0; /* CMD2 */ tc_wmb();
605 REG(vdac, bt_reg) = 0xff; /* PRM */ tc_wmb();
606 REG(vdac, bt_reg) = 0; /* 205 */ tc_wmb();
607 REG(vdac, bt_reg) = 0x0; /* PBM */ tc_wmb();
608 REG(vdac, bt_reg) = 0; /* 207 */ tc_wmb();
609 REG(vdac, bt_reg) = 0x0; /* ORM */ tc_wmb();
610 REG(vdac, bt_reg) = 0x0; /* OBM */ tc_wmb();
611 REG(vdac, bt_reg) = 0x0; /* ILV */ tc_wmb();
612 REG(vdac, bt_reg) = 0x0; /* TEST */ tc_wmb();
613
614 SELECT(vdac, BT459_IREG_CCR);
615 REG(vdac, bt_reg) = 0x0; tc_wmb();
616 REG(vdac, bt_reg) = 0x0; tc_wmb();
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
629 /* build sane colormap */
630 SELECT(vdac, 0);
631 for (i = 0; i < CMAP_SIZE; i++) {
632 REG(vdac, bt_cmap) = rasops_cmap[3 * i + 0];
633 tc_wmb();
634 REG(vdac, bt_cmap) = rasops_cmap[3 * i + 1];
635 tc_wmb();
636 REG(vdac, bt_cmap) = rasops_cmap[3 * i + 2];
637 tc_wmb();
638 }
639
640 /* clear out cursor image */
641 SELECT(vdac, BT459_IREG_CRAM_BASE);
642 for (i = 0; i < 1024; i++)
643 REG(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 SELECT(vdac, BT459_IREG_CCOLOR_1);
651 REG(vdac, bt_reg) = 0xff; tc_wmb();
652 REG(vdac, bt_reg) = 0xff; tc_wmb();
653 REG(vdac, bt_reg) = 0xff; tc_wmb();
654
655 REG(vdac, bt_reg) = 0; tc_wmb();
656 REG(vdac, bt_reg) = 0; tc_wmb();
657 REG(vdac, bt_reg) = 0; tc_wmb();
658
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
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
807 x += sc->sc_cursor.cc_magic.x;
808 y += sc->sc_cursor.cc_magic.y;
809
810 s = spltty();
811
812 SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
813 REG(vdac, bt_reg) = x; tc_wmb();
814 REG(vdac, bt_reg) = x >> 8; tc_wmb();
815 REG(vdac, bt_reg) = y; tc_wmb();
816 REG(vdac, bt_reg) = y >> 8; tc_wmb();
817
818 splx(s);
819 }
820