cfb.c revision 1.30 1 /* $NetBSD: cfb.c,v 1.30 2001/11/13 06:26:09 lukem 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>
34 __KERNEL_RCSID(0, "$NetBSD: cfb.c,v 1.30 2001/11/13 06:26:09 lukem Exp $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
41 #include <sys/buf.h>
42 #include <sys/ioctl.h>
43
44 #include <machine/bus.h>
45 #include <machine/intr.h>
46
47 #include <dev/wscons/wsconsio.h>
48 #include <dev/wscons/wsdisplayvar.h>
49
50 #include <dev/rasops/rasops.h>
51 #include <dev/wsfont/wsfont.h>
52
53 #include <dev/tc/tcvar.h>
54 #include <dev/ic/bt459reg.h>
55
56 #include <uvm/uvm_extern.h>
57
58 #if defined(pmax)
59 #define machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
60 #endif
61
62 #if defined(alpha)
63 #define machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
64 #endif
65
66 /*
67 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have
68 * obscure register layout such as 2nd and 3rd Bt459 registers are
69 * adjacent each other in a word, i.e.,
70 * struct bt459triplet {
71 * struct {
72 * u_int8_t u0;
73 * u_int8_t u1;
74 * u_int8_t u2;
75 * unsigned :8;
76 * } bt_lo;
77 * ...
78 * Although CX has single Bt459, 32bit R/W can be done w/o any trouble.
79 * struct bt459reg {
80 * u_int32_t bt_lo;
81 * u_int32_t bt_hi;
82 * u_int32_t bt_reg;
83 * u_int32_t bt_cmap;
84 * };
85 */
86
87 /* Bt459 hardware registers */
88 #define bt_lo 0
89 #define bt_hi 1
90 #define bt_reg 2
91 #define bt_cmap 3
92
93 #define REG(base, index) *((u_int32_t *)(base) + (index))
94 #define SELECT(vdac, regno) do { \
95 REG(vdac, bt_lo) = ((regno) & 0x00ff); \
96 REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8; \
97 tc_wmb(); \
98 } while (0)
99
100 struct hwcmap256 {
101 #define CMAP_SIZE 256 /* 256 R/G/B entries */
102 u_int8_t r[CMAP_SIZE];
103 u_int8_t g[CMAP_SIZE];
104 u_int8_t b[CMAP_SIZE];
105 };
106
107 struct hwcursor64 {
108 struct wsdisplay_curpos cc_pos;
109 struct wsdisplay_curpos cc_hot;
110 struct wsdisplay_curpos cc_size;
111 struct wsdisplay_curpos cc_magic;
112 #define CURSOR_MAX_SIZE 64
113 u_int8_t cc_color[6];
114 u_int64_t cc_image[64 + 64];
115 };
116
117 struct cfb_softc {
118 struct device sc_dev;
119 vaddr_t sc_vaddr;
120 size_t sc_size;
121 struct rasops_info *sc_ri;
122 struct hwcmap256 sc_cmap; /* software copy of colormap */
123 struct hwcursor64 sc_cursor; /* software copy of cursor */
124 int sc_blanked;
125 int sc_curenb; /* cursor sprite enabled */
126 int sc_changed; /* need update of hardware */
127 #define WSDISPLAY_CMAP_DOLUT 0x20
128 int nscreens;
129 };
130
131 #define CX_MAGIC_X 220
132 #define CX_MAGIC_Y 35
133
134 #define CX_FB_OFFSET 0x000000
135 #define CX_FB_SIZE 0x100000
136 #define CX_BT459_OFFSET 0x200000
137 #define CX_OFFSET_IREQ 0x300000 /* Interrupt req. control */
138
139 static int cfbmatch __P((struct device *, struct cfdata *, void *));
140 static void cfbattach __P((struct device *, struct device *, void *));
141
142 const struct cfattach cfb_ca = {
143 sizeof(struct cfb_softc), cfbmatch, cfbattach,
144 };
145
146 static void cfb_common_init __P((struct rasops_info *));
147 static struct rasops_info cfb_console_ri;
148 static tc_addr_t cfb_consaddr;
149
150 static struct wsscreen_descr cfb_stdscreen = {
151 "std", 0, 0,
152 0, /* textops */
153 0, 0,
154 WSSCREEN_REVERSE
155 };
156
157 static const struct wsscreen_descr *_cfb_scrlist[] = {
158 &cfb_stdscreen,
159 };
160
161 static const struct wsscreen_list cfb_screenlist = {
162 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
163 };
164
165 static int cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
166 static paddr_t cfbmmap __P((void *, off_t, int));
167
168 static int cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
169 void **, int *, int *, long *));
170 static void cfb_free_screen __P((void *, void *));
171 static int cfb_show_screen __P((void *, void *, int,
172 void (*) (void *, int, int), void *));
173
174 static const struct wsdisplay_accessops cfb_accessops = {
175 cfbioctl,
176 cfbmmap,
177 cfb_alloc_screen,
178 cfb_free_screen,
179 cfb_show_screen,
180 0 /* load_font */
181 };
182
183 int cfb_cnattach __P((tc_addr_t));
184 static int cfbintr __P((void *));
185 static void cfbhwinit __P((caddr_t));
186
187 static int get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
188 static int set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
189 static int set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
190 static int get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
191 static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *));
192
193 /*
194 * Compose 2 bit/pixel cursor image. Bit order will be reversed.
195 * M M M M I I I I M I M I M I M I
196 * [ before ] [ after ]
197 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3
198 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7
199 */
200 static const u_int8_t shuffle[256] = {
201 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
202 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
203 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
204 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
205 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
206 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
207 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
208 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
209 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
210 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
211 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
212 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
213 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
214 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
215 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
216 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
217 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
218 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
219 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
220 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
221 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
222 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
223 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
224 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
225 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
226 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
227 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
228 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
229 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
230 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
231 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
232 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
233 };
234
235 static int
236 cfbmatch(parent, match, aux)
237 struct device *parent;
238 struct cfdata *match;
239 void *aux;
240 {
241 struct tc_attach_args *ta = aux;
242
243 if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
244 return (0);
245
246 return (1);
247 }
248
249 static void
250 cfbattach(parent, self, aux)
251 struct device *parent, *self;
252 void *aux;
253 {
254 struct cfb_softc *sc = (struct cfb_softc *)self;
255 struct tc_attach_args *ta = aux;
256 struct rasops_info *ri;
257 struct wsemuldisplaydev_attach_args waa;
258 struct hwcmap256 *cm;
259 const u_int8_t *p;
260 int console, index;
261
262 console = (ta->ta_addr == cfb_consaddr);
263 if (console) {
264 sc->sc_ri = ri = &cfb_console_ri;
265 sc->nscreens = 1;
266 }
267 else {
268 MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
269 M_DEVBUF, M_NOWAIT);
270 if (ri == NULL) {
271 printf(": can't alloc memory\n");
272 return;
273 }
274 memset(ri, 0, sizeof(struct rasops_info));
275
276 ri->ri_hw = (void *)ta->ta_addr;
277 cfb_common_init(ri);
278 sc->sc_ri = ri;
279 }
280 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
281
282 cm = &sc->sc_cmap;
283 p = rasops_cmap;
284 for (index = 0; index < CMAP_SIZE; index++, p += 3) {
285 cm->r[index] = p[0];
286 cm->g[index] = p[1];
287 cm->b[index] = p[2];
288 }
289
290 sc->sc_vaddr = ta->ta_addr;
291 sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
292 sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
293 sc->sc_blanked = sc->sc_curenb = 0;
294
295 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
296
297 /* clear any pending interrupts */
298 *(u_int8_t *)((caddr_t)ri->ri_hw + CX_OFFSET_IREQ) = 0;
299
300 waa.console = console;
301 waa.scrdata = &cfb_screenlist;
302 waa.accessops = &cfb_accessops;
303 waa.accesscookie = sc;
304
305 config_found(self, &waa, wsemuldisplaydevprint);
306 }
307
308 static void
309 cfb_common_init(ri)
310 struct rasops_info *ri;
311 {
312 caddr_t base;
313 int cookie;
314
315 base = (caddr_t)ri->ri_hw;
316
317 /* initialize colormap and cursor hardware */
318 cfbhwinit(base);
319
320 ri->ri_flg = RI_CENTER;
321 ri->ri_depth = 8;
322 ri->ri_width = 1024;
323 ri->ri_height = 864;
324 ri->ri_stride = 1024;
325 ri->ri_bits = base + CX_FB_OFFSET;
326
327 /* clear the screen */
328 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
329
330 wsfont_init();
331 /* prefer 12 pixel wide font */
332 if ((cookie = wsfont_find(NULL, 12, 0, 0)) <= 0)
333 cookie = wsfont_find(NULL, 0, 0, 0);
334 if (cookie <= 0) {
335 printf("cfb: font table is empty\n");
336 return;
337 }
338
339 if (wsfont_lock(cookie, &ri->ri_font,
340 WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
341 printf("cfb: couldn't lock font\n");
342 return;
343 }
344 ri->ri_wsfcookie = cookie;
345
346 rasops_init(ri, 34, 80);
347
348 /* XXX shouldn't be global */
349 cfb_stdscreen.nrows = ri->ri_rows;
350 cfb_stdscreen.ncols = ri->ri_cols;
351 cfb_stdscreen.textops = &ri->ri_ops;
352 cfb_stdscreen.capabilities = ri->ri_caps;
353 }
354
355 static int
356 cfbioctl(v, cmd, data, flag, p)
357 void *v;
358 u_long cmd;
359 caddr_t data;
360 int flag;
361 struct proc *p;
362 {
363 struct cfb_softc *sc = v;
364 struct rasops_info *ri = sc->sc_ri;
365 int turnoff;
366
367 switch (cmd) {
368 case WSDISPLAYIO_GTYPE:
369 *(u_int *)data = WSDISPLAY_TYPE_CFB;
370 return (0);
371
372 case WSDISPLAYIO_GINFO:
373 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
374 wsd_fbip->height = ri->ri_height;
375 wsd_fbip->width = ri->ri_width;
376 wsd_fbip->depth = ri->ri_depth;
377 wsd_fbip->cmsize = CMAP_SIZE;
378 #undef fbt
379 return (0);
380
381 case WSDISPLAYIO_GETCMAP:
382 return get_cmap(sc, (struct wsdisplay_cmap *)data);
383
384 case WSDISPLAYIO_PUTCMAP:
385 return set_cmap(sc, (struct wsdisplay_cmap *)data);
386
387 case WSDISPLAYIO_SVIDEO:
388 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
389 if ((sc->sc_blanked == 0) ^ turnoff) {
390 sc->sc_blanked = turnoff;
391 /* XXX later XXX */
392 }
393 return (0);
394
395 case WSDISPLAYIO_GVIDEO:
396 *(u_int *)data = sc->sc_blanked ?
397 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
398 return (0);
399
400 case WSDISPLAYIO_GCURPOS:
401 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
402 return (0);
403
404 case WSDISPLAYIO_SCURPOS:
405 set_curpos(sc, (struct wsdisplay_curpos *)data);
406 sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
407 return (0);
408
409 case WSDISPLAYIO_GCURMAX:
410 ((struct wsdisplay_curpos *)data)->x =
411 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
412 return (0);
413
414 case WSDISPLAYIO_GCURSOR:
415 return get_cursor(sc, (struct wsdisplay_cursor *)data);
416
417 case WSDISPLAYIO_SCURSOR:
418 return set_cursor(sc, (struct wsdisplay_cursor *)data);
419 }
420 return ENOTTY;
421 }
422
423 paddr_t
424 cfbmmap(v, offset, prot)
425 void *v;
426 off_t offset;
427 int prot;
428 {
429 struct cfb_softc *sc = v;
430
431 if (offset >= CX_FB_SIZE || offset < 0)
432 return (-1);
433 return machine_btop(sc->sc_vaddr + CX_FB_OFFSET + offset);
434 }
435
436 static int
437 cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
438 void *v;
439 const struct wsscreen_descr *type;
440 void **cookiep;
441 int *curxp, *curyp;
442 long *attrp;
443 {
444 struct cfb_softc *sc = v;
445 struct rasops_info *ri = sc->sc_ri;
446 long defattr;
447
448 if (sc->nscreens > 0)
449 return (ENOMEM);
450
451 *cookiep = ri; /* one and only for now */
452 *curxp = 0;
453 *curyp = 0;
454 (*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
455 *attrp = defattr;
456 sc->nscreens++;
457 return (0);
458 }
459
460 static void
461 cfb_free_screen(v, cookie)
462 void *v;
463 void *cookie;
464 {
465 struct cfb_softc *sc = v;
466
467 if (sc->sc_ri == &cfb_console_ri)
468 panic("cfb_free_screen: console");
469
470 sc->nscreens--;
471 }
472
473 static int
474 cfb_show_screen(v, cookie, waitok, cb, cbarg)
475 void *v;
476 void *cookie;
477 int waitok;
478 void (*cb) __P((void *, int, int));
479 void *cbarg;
480 {
481
482 return (0);
483 }
484
485 /* EXPORT */ int
486 cfb_cnattach(addr)
487 tc_addr_t addr;
488 {
489 struct rasops_info *ri;
490 long defattr;
491
492 ri = &cfb_console_ri;
493 ri->ri_hw = (void *)addr;
494 cfb_common_init(ri);
495 (*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
496 wsdisplay_cnattach(&cfb_stdscreen, ri, 0, 0, defattr);
497 cfb_consaddr = addr;
498 return(0);
499 }
500
501 static int
502 cfbintr(arg)
503 void *arg;
504 {
505 struct cfb_softc *sc = arg;
506 caddr_t base, vdac;
507 int v;
508
509 base = (caddr_t)sc->sc_ri->ri_hw;
510 *(u_int8_t *)(base + CX_OFFSET_IREQ) = 0;
511 if (sc->sc_changed == 0)
512 return (1);
513
514 vdac = base + CX_BT459_OFFSET;
515 v = sc->sc_changed;
516 if (v & WSDISPLAY_CURSOR_DOCUR) {
517 SELECT(vdac, BT459_IREG_CCR);
518 REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
519 }
520 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
521 int x, y;
522
523 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
524 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
525
526 x += sc->sc_cursor.cc_magic.x;
527 y += sc->sc_cursor.cc_magic.y;
528
529 SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
530 REG(vdac, bt_reg) = x; tc_wmb();
531 REG(vdac, bt_reg) = x >> 8; tc_wmb();
532 REG(vdac, bt_reg) = y; tc_wmb();
533 REG(vdac, bt_reg) = y >> 8; tc_wmb();
534 }
535 if (v & WSDISPLAY_CURSOR_DOCMAP) {
536 u_int8_t *cp = sc->sc_cursor.cc_color;
537
538 SELECT(vdac, BT459_IREG_CCOLOR_2);
539 REG(vdac, bt_reg) = cp[1]; tc_wmb();
540 REG(vdac, bt_reg) = cp[3]; tc_wmb();
541 REG(vdac, bt_reg) = cp[5]; tc_wmb();
542
543 REG(vdac, bt_reg) = cp[0]; tc_wmb();
544 REG(vdac, bt_reg) = cp[2]; tc_wmb();
545 REG(vdac, bt_reg) = cp[4]; tc_wmb();
546 }
547 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
548 u_int8_t *ip, *mp, img, msk;
549 u_int8_t u;
550 int bcnt;
551
552 ip = (u_int8_t *)sc->sc_cursor.cc_image;
553 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
554
555 bcnt = 0;
556 SELECT(vdac, BT459_IREG_CRAM_BASE+0);
557 /* 64 pixel scan line is consisted with 16 byte cursor ram */
558 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
559 /* pad right half 32 pixel when smaller than 33 */
560 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
561 REG(vdac, bt_reg) = 0; tc_wmb();
562 REG(vdac, bt_reg) = 0; tc_wmb();
563 }
564 else {
565 img = *ip++;
566 msk = *mp++;
567 img &= msk; /* cookie off image */
568 u = (msk & 0x0f) << 4 | (img & 0x0f);
569 REG(vdac, bt_reg) = shuffle[u]; tc_wmb();
570 u = (msk & 0xf0) | (img & 0xf0) >> 4;
571 REG(vdac, bt_reg) = shuffle[u]; tc_wmb();
572 }
573 bcnt += 2;
574 }
575 /* pad unoccupied scan lines */
576 while (bcnt < CURSOR_MAX_SIZE * 16) {
577 REG(vdac, bt_reg) = 0; tc_wmb();
578 REG(vdac, bt_reg) = 0; tc_wmb();
579 bcnt += 2;
580 }
581 }
582 if (v & WSDISPLAY_CMAP_DOLUT) {
583 struct hwcmap256 *cm = &sc->sc_cmap;
584 int index;
585
586 SELECT(vdac, 0);
587 for (index = 0; index < CMAP_SIZE; index++) {
588 REG(vdac, bt_cmap) = cm->r[index]; tc_wmb();
589 REG(vdac, bt_cmap) = cm->g[index]; tc_wmb();
590 REG(vdac, bt_cmap) = cm->b[index]; tc_wmb();
591 }
592 }
593 sc->sc_changed = 0;
594 return (1);
595 }
596
597 static void
598 cfbhwinit(cfbbase)
599 caddr_t cfbbase;
600 {
601 caddr_t vdac = cfbbase + CX_BT459_OFFSET;
602 const u_int8_t *p;
603 int i;
604
605 SELECT(vdac, BT459_IREG_COMMAND_0);
606 REG(vdac, bt_reg) = 0x40; /* CMD0 */ tc_wmb();
607 REG(vdac, bt_reg) = 0x0; /* CMD1 */ tc_wmb();
608 REG(vdac, bt_reg) = 0xc0; /* CMD2 */ tc_wmb();
609 REG(vdac, bt_reg) = 0xff; /* PRM */ tc_wmb();
610 REG(vdac, bt_reg) = 0; /* 205 */ tc_wmb();
611 REG(vdac, bt_reg) = 0x0; /* PBM */ tc_wmb();
612 REG(vdac, bt_reg) = 0; /* 207 */ tc_wmb();
613 REG(vdac, bt_reg) = 0x0; /* ORM */ tc_wmb();
614 REG(vdac, bt_reg) = 0x0; /* OBM */ tc_wmb();
615 REG(vdac, bt_reg) = 0x0; /* ILV */ tc_wmb();
616 REG(vdac, bt_reg) = 0x0; /* TEST */ tc_wmb();
617
618 SELECT(vdac, BT459_IREG_CCR);
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 REG(vdac, bt_reg) = 0x0; tc_wmb();
631 REG(vdac, bt_reg) = 0x0; tc_wmb();
632
633 /* build sane colormap */
634 SELECT(vdac, 0);
635 p = rasops_cmap;
636 for (i = 0; i < CMAP_SIZE; i++, p += 3) {
637 REG(vdac, bt_cmap) = p[0]; tc_wmb();
638 REG(vdac, bt_cmap) = p[1]; tc_wmb();
639 REG(vdac, bt_cmap) = p[2]; tc_wmb();
640 }
641
642 /* clear out cursor image */
643 SELECT(vdac, BT459_IREG_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_IREG_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 sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
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 u_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
738 if (v & WSDISPLAY_CURSOR_DOCUR)
739 sc->sc_curenb = p->enable;
740 if (v & WSDISPLAY_CURSOR_DOPOS)
741 set_curpos(sc, &p->pos);
742 if (v & WSDISPLAY_CURSOR_DOHOT)
743 cc->cc_hot = p->hot;
744 if (v & WSDISPLAY_CURSOR_DOCMAP) {
745 copyin(p->cmap.red, &cc->cc_color[index], count);
746 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
747 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
748 }
749 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
750 cc->cc_size = p->size;
751 memset(cc->cc_image, 0, sizeof cc->cc_image);
752 copyin(p->image, cc->cc_image, icount);
753 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
754 }
755 sc->sc_changed |= v;
756
757 return (0);
758 #undef cc
759 }
760
761 static int
762 get_cursor(sc, p)
763 struct cfb_softc *sc;
764 struct wsdisplay_cursor *p;
765 {
766 return (ENOTTY); /* XXX */
767 }
768
769 static void
770 set_curpos(sc, curpos)
771 struct cfb_softc *sc;
772 struct wsdisplay_curpos *curpos;
773 {
774 struct rasops_info *ri = sc->sc_ri;
775 int x = curpos->x, y = curpos->y;
776
777 if (y < 0)
778 y = 0;
779 else if (y > ri->ri_height)
780 y = ri->ri_height;
781 if (x < 0)
782 x = 0;
783 else if (x > ri->ri_width)
784 x = ri->ri_width;
785 sc->sc_cursor.cc_pos.x = x;
786 sc->sc_cursor.cc_pos.y = y;
787 }
788