cfb.c revision 1.24 1 /* $NetBSD: cfb.c,v 1.24 2000/10/27 07:24:04 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.24 2000/10/27 07:24:04 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 struct hwcmap256 *cm;
338 const u_int8_t *p;
339 int console, index;
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 p = rasops_cmap;
356 for (index = 0; index < CMAP_SIZE; index++) {
357 cm->r[index] = p[0];
358 cm->g[index] = p[1];
359 cm->b[index] = p[2];
360 }
361
362 sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
363 sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
364
365 /* Establish an interrupt handler, and clear any pending interrupts */
366 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
367 *(u_int8_t *)(sc->sc_dc->dc_vaddr + CX_OFFSET_IREQ) = 0;
368
369 waa.console = console;
370 waa.scrdata = &cfb_screenlist;
371 waa.accessops = &cfb_accessops;
372 waa.accesscookie = sc;
373
374 config_found(self, &waa, wsemuldisplaydevprint);
375 }
376
377 static int
378 cfbioctl(v, cmd, data, flag, p)
379 void *v;
380 u_long cmd;
381 caddr_t data;
382 int flag;
383 struct proc *p;
384 {
385 struct cfb_softc *sc = v;
386 struct fb_devconfig *dc = sc->sc_dc;
387 int turnoff;
388
389 switch (cmd) {
390 case WSDISPLAYIO_GTYPE:
391 *(u_int *)data = WSDISPLAY_TYPE_CFB;
392 return (0);
393
394 case WSDISPLAYIO_GINFO:
395 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
396 wsd_fbip->height = sc->sc_dc->dc_ht;
397 wsd_fbip->width = sc->sc_dc->dc_wid;
398 wsd_fbip->depth = sc->sc_dc->dc_depth;
399 wsd_fbip->cmsize = CMAP_SIZE;
400 #undef fbt
401 return (0);
402
403 case WSDISPLAYIO_GETCMAP:
404 return get_cmap(sc, (struct wsdisplay_cmap *)data);
405
406 case WSDISPLAYIO_PUTCMAP:
407 return set_cmap(sc, (struct wsdisplay_cmap *)data);
408
409 case WSDISPLAYIO_SVIDEO:
410 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
411 if ((dc->dc_blanked == 0) ^ turnoff) {
412 dc->dc_blanked = turnoff;
413 /* XXX later XXX */
414 }
415 return (0);
416
417 case WSDISPLAYIO_GVIDEO:
418 *(u_int *)data = dc->dc_blanked ?
419 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
420 return (0);
421
422 case WSDISPLAYIO_GCURPOS:
423 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
424 return (0);
425
426 case WSDISPLAYIO_SCURPOS:
427 set_curpos(sc, (struct wsdisplay_curpos *)data);
428 bt459_set_curpos(sc);
429 return (0);
430
431 case WSDISPLAYIO_GCURMAX:
432 ((struct wsdisplay_curpos *)data)->x =
433 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
434 return (0);
435
436 case WSDISPLAYIO_GCURSOR:
437 return get_cursor(sc, (struct wsdisplay_cursor *)data);
438
439 case WSDISPLAYIO_SCURSOR:
440 return set_cursor(sc, (struct wsdisplay_cursor *)data);
441 }
442 return ENOTTY;
443 }
444
445 paddr_t
446 cfbmmap(v, offset, prot)
447 void *v;
448 off_t offset;
449 int prot;
450 {
451 struct cfb_softc *sc = v;
452
453 if (offset >= CX_FB_SIZE || offset < 0)
454 return (-1);
455 return machine_btop(sc->sc_dc->dc_paddr + offset);
456 }
457
458 static int
459 cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
460 void *v;
461 const struct wsscreen_descr *type;
462 void **cookiep;
463 int *curxp, *curyp;
464 long *attrp;
465 {
466 struct cfb_softc *sc = v;
467 long defattr;
468
469 if (sc->nscreens > 0)
470 return (ENOMEM);
471
472 *cookiep = &sc->sc_dc->rinfo; /* one and only for now */
473 *curxp = 0;
474 *curyp = 0;
475 (*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr);
476 *attrp = defattr;
477 sc->nscreens++;
478 return (0);
479 }
480
481 static void
482 cfb_free_screen(v, cookie)
483 void *v;
484 void *cookie;
485 {
486 struct cfb_softc *sc = v;
487
488 if (sc->sc_dc == &cfb_console_dc)
489 panic("cfb_free_screen: console");
490
491 sc->nscreens--;
492 }
493
494 static int
495 cfb_show_screen(v, cookie, waitok, cb, cbarg)
496 void *v;
497 void *cookie;
498 int waitok;
499 void (*cb) __P((void *, int, int));
500 void *cbarg;
501 {
502
503 return (0);
504 }
505
506 /* EXPORT */ int
507 cfb_cnattach(addr)
508 tc_addr_t addr;
509 {
510 struct fb_devconfig *dcp = &cfb_console_dc;
511 long defattr;
512
513 cfb_getdevconfig(addr, dcp);
514 (*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr);
515 wsdisplay_cnattach(&cfb_stdscreen, &dcp->rinfo, 0, 0, defattr);
516 cfb_consaddr = addr;
517 return(0);
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_IREG_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_IREG_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_IREG_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 const u_int8_t *p;
608 int i;
609
610 SELECT(vdac, BT459_IREG_COMMAND_0);
611 REG(vdac, bt_reg) = 0x40; /* CMD0 */ tc_wmb();
612 REG(vdac, bt_reg) = 0x0; /* CMD1 */ tc_wmb();
613 REG(vdac, bt_reg) = 0xc0; /* CMD2 */ tc_wmb();
614 REG(vdac, bt_reg) = 0xff; /* PRM */ tc_wmb();
615 REG(vdac, bt_reg) = 0; /* 205 */ tc_wmb();
616 REG(vdac, bt_reg) = 0x0; /* PBM */ tc_wmb();
617 REG(vdac, bt_reg) = 0; /* 207 */ tc_wmb();
618 REG(vdac, bt_reg) = 0x0; /* ORM */ tc_wmb();
619 REG(vdac, bt_reg) = 0x0; /* OBM */ tc_wmb();
620 REG(vdac, bt_reg) = 0x0; /* ILV */ tc_wmb();
621 REG(vdac, bt_reg) = 0x0; /* TEST */ tc_wmb();
622
623 SELECT(vdac, BT459_IREG_CCR);
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 REG(vdac, bt_reg) = 0x0; tc_wmb();
637
638 /* build sane colormap */
639 SELECT(vdac, 0);
640 p = rasops_cmap;
641 for (i = 0; i < CMAP_SIZE; i++) {
642 REG(vdac, bt_cmap) = p[0]; tc_wmb();
643 REG(vdac, bt_cmap) = p[1]; tc_wmb();
644 REG(vdac, bt_cmap) = p[2]; tc_wmb();
645 }
646
647 /* clear out cursor image */
648 SELECT(vdac, BT459_IREG_CRAM_BASE);
649 for (i = 0; i < 1024; i++)
650 REG(vdac, bt_reg) = 0xff; tc_wmb();
651
652 /*
653 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
654 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for
655 * image color. CCOLOR_1 will be never used.
656 */
657 SELECT(vdac, BT459_IREG_CCOLOR_1);
658 REG(vdac, bt_reg) = 0xff; tc_wmb();
659 REG(vdac, bt_reg) = 0xff; tc_wmb();
660 REG(vdac, bt_reg) = 0xff; tc_wmb();
661
662 REG(vdac, bt_reg) = 0; tc_wmb();
663 REG(vdac, bt_reg) = 0; tc_wmb();
664 REG(vdac, bt_reg) = 0; tc_wmb();
665
666 REG(vdac, bt_reg) = 0xff; tc_wmb();
667 REG(vdac, bt_reg) = 0xff; tc_wmb();
668 REG(vdac, bt_reg) = 0xff; tc_wmb();
669 }
670
671 static int
672 get_cmap(sc, p)
673 struct cfb_softc *sc;
674 struct wsdisplay_cmap *p;
675 {
676 u_int index = p->index, count = p->count;
677
678 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
679 return (EINVAL);
680
681 if (!uvm_useracc(p->red, count, B_WRITE) ||
682 !uvm_useracc(p->green, count, B_WRITE) ||
683 !uvm_useracc(p->blue, count, B_WRITE))
684 return (EFAULT);
685
686 copyout(&sc->sc_cmap.r[index], p->red, count);
687 copyout(&sc->sc_cmap.g[index], p->green, count);
688 copyout(&sc->sc_cmap.b[index], p->blue, count);
689
690 return (0);
691 }
692
693 static int
694 set_cmap(sc, p)
695 struct cfb_softc *sc;
696 struct wsdisplay_cmap *p;
697 {
698 u_int index = p->index, count = p->count;
699
700 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
701 return (EINVAL);
702
703 if (!uvm_useracc(p->red, count, B_READ) ||
704 !uvm_useracc(p->green, count, B_READ) ||
705 !uvm_useracc(p->blue, count, B_READ))
706 return (EFAULT);
707
708 copyin(p->red, &sc->sc_cmap.r[index], count);
709 copyin(p->green, &sc->sc_cmap.g[index], count);
710 copyin(p->blue, &sc->sc_cmap.b[index], count);
711
712 sc->sc_changed |= DATA_CMAP_CHANGED;
713
714 return (0);
715 }
716
717 static int
718 set_cursor(sc, p)
719 struct cfb_softc *sc;
720 struct wsdisplay_cursor *p;
721 {
722 #define cc (&sc->sc_cursor)
723 int v, index, count, icount;
724
725 v = p->which;
726 if (v & WSDISPLAY_CURSOR_DOCMAP) {
727 index = p->cmap.index;
728 count = p->cmap.count;
729 if (index >= 2 || (index + count) > 2)
730 return (EINVAL);
731 if (!uvm_useracc(p->cmap.red, count, B_READ) ||
732 !uvm_useracc(p->cmap.green, count, B_READ) ||
733 !uvm_useracc(p->cmap.blue, count, B_READ))
734 return (EFAULT);
735 }
736 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
737 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
738 return (EINVAL);
739 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
740 if (!uvm_useracc(p->image, icount, B_READ) ||
741 !uvm_useracc(p->mask, icount, B_READ))
742 return (EFAULT);
743 }
744 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
745 if (v & WSDISPLAY_CURSOR_DOCUR)
746 cc->cc_hot = p->hot;
747 if (v & WSDISPLAY_CURSOR_DOPOS)
748 set_curpos(sc, &p->pos);
749 bt459_set_curpos(sc);
750 }
751
752 sc->sc_changed = 0;
753 if (v & WSDISPLAY_CURSOR_DOCUR) {
754 sc->sc_curenb = p->enable;
755 sc->sc_changed |= DATA_ENB_CHANGED;
756 }
757 if (v & WSDISPLAY_CURSOR_DOCMAP) {
758 copyin(p->cmap.red, &cc->cc_color[index], count);
759 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
760 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
761 sc->sc_changed |= DATA_CURCMAP_CHANGED;
762 }
763 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
764 cc->cc_size = p->size;
765 memset(cc->cc_image, 0, sizeof cc->cc_image);
766 copyin(p->image, cc->cc_image, icount);
767 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
768 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
769 }
770
771 return (0);
772 #undef cc
773 }
774
775 static int
776 get_cursor(sc, p)
777 struct cfb_softc *sc;
778 struct wsdisplay_cursor *p;
779 {
780 return (ENOTTY); /* XXX */
781 }
782
783 static void
784 set_curpos(sc, curpos)
785 struct cfb_softc *sc;
786 struct wsdisplay_curpos *curpos;
787 {
788 struct fb_devconfig *dc = sc->sc_dc;
789 int x = curpos->x, y = curpos->y;
790
791 if (y < 0)
792 y = 0;
793 else if (y > dc->dc_ht)
794 y = dc->dc_ht;
795 if (x < 0)
796 x = 0;
797 else if (x > dc->dc_wid)
798 x = dc->dc_wid;
799 sc->sc_cursor.cc_pos.x = x;
800 sc->sc_cursor.cc_pos.y = y;
801 }
802
803 void
804 bt459_set_curpos(sc)
805 struct cfb_softc *sc;
806 {
807 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
808 struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET);
809 int x, y, s;
810
811 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
812 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
813
814 x += sc->sc_cursor.cc_magic.x;
815 y += sc->sc_cursor.cc_magic.y;
816
817 s = spltty();
818
819 SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
820 REG(vdac, bt_reg) = x; tc_wmb();
821 REG(vdac, bt_reg) = x >> 8; tc_wmb();
822 REG(vdac, bt_reg) = y; tc_wmb();
823 REG(vdac, bt_reg) = y >> 8; tc_wmb();
824
825 splx(s);
826 }
827