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