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