mfb.c revision 1.3 1 /* $NetBSD: mfb.c,v 1.3 1998/11/09 03:58:05 nisimura Exp $ */
2
3 /*
4 * Copyright (c) 1998 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: mfb.c,v 1.3 1998/11/09 03:58:05 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 #include <vm/vm.h>
45
46 #include <machine/bus.h>
47 #include <machine/intr.h>
48
49 #include <dev/rcons/raster.h>
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/wscons/wscons_raster.h>
52 #include <dev/wscons/wsdisplayvar.h>
53 #include <machine/autoconf.h>
54
55 #include <dev/tc/tcvar.h>
56 #include <dev/ic/bt431reg.h>
57
58 #include "opt_uvm.h"
59 #if defined(UVM)
60 #include <uvm/uvm_extern.h>
61 #define useracc uvm_useracc
62 #endif
63
64 /* XXX BUS'IFYING XXX */
65
66 #if defined(__pmax__)
67 #define machine_btop(x) mips_btop(x)
68 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG0_TO_PHYS(x)
69
70 struct bt455reg {
71 u_int8_t bt_reg;
72 unsigned : 24;
73 u_int8_t bt_cmap;
74 unsigned : 24;
75 u_int8_t bt_clr;
76 unsigned : 24;
77 u_int8_t bt_ovly;
78 };
79
80 /* it's really painful to manipulate 'twined' registers... */
81 struct bt431reg {
82 u_int16_t bt_lo;
83 unsigned : 16;
84 u_int16_t bt_hi;
85 unsigned : 16;
86 u_int16_t bt_ram;
87 unsigned : 16;
88 u_int16_t bt_ctl;
89 };
90
91 #endif
92
93 #if defined(__alpha__) || defined(alpha)
94 /*
95 * Digital UNIX never supports PMAG-AA
96 */
97 #define machine_btop(x) alpha_btop(x)
98 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
99
100 struct bt455reg {
101 u_int32_t bt_reg;
102 u_int32_t bt_cmap;
103 u_int32_t bt_clr;
104 u_int32_t bt_ovly;
105 };
106
107 /*
108 * N.B. a paif of Bt431s are located adjascently.
109 * struct bt431twin {
110 * struct {
111 * u_int8_t u0; for sprite image
112 * u_int8_t u1; for sprite mask
113 * unsigned :16;
114 * } bt_lo;
115 * ...
116 */
117 struct bt431reg {
118 u_int32_t bt_lo;
119 u_int32_t bt_hi;
120 u_int32_t bt_ram;
121 u_int32_t bt_ctl;
122 };
123 #endif
124
125 /* XXX XXX XXX */
126
127 struct fb_devconfig {
128 vaddr_t dc_vaddr; /* memory space virtual base address */
129 paddr_t dc_paddr; /* memory space physical base address */
130 vsize_t dc_size; /* size of slot memory */
131 int dc_wid; /* width of frame buffer */
132 int dc_ht; /* height of frame buffer */
133 int dc_depth; /* depth, bits per pixel */
134 int dc_rowbytes; /* bytes in a FB scan line */
135 vaddr_t dc_videobase; /* base of flat frame buffer */
136 struct raster dc_raster; /* raster description */
137 struct rcons dc_rcons; /* raster blitter control info */
138 int dc_blanked; /* currently has video disabled */
139 };
140
141 struct hwcursor {
142 struct wsdisplay_curpos cc_pos;
143 struct wsdisplay_curpos cc_hot;
144 struct wsdisplay_curpos cc_size;
145 #define CURSOR_MAX_SIZE 64
146 u_int8_t cc_color[6];
147 u_int64_t cc_image[64 + 64];
148 };
149
150 struct mfb_softc {
151 struct device sc_dev;
152 struct fb_devconfig *sc_dc; /* device configuration */
153 struct hwcursor sc_cursor; /* software copy of cursor */
154 int sc_curenb; /* cursor sprite enabled */
155 int sc_changed; /* need update of colormap */
156 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */
157 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */
158 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */
159 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */
160 #define DATA_ALL_CHANGED 0x0f
161 int nscreens;
162 short magic_x, magic_y; /* MX cursor location offset */
163 #define MX_MAGIC_X 360
164 #define MX_MAGIC_Y 36
165 };
166
167 #define MX_FB_OFFSET 0x200000
168 #define MX_FB_SIZE 0x40000
169 #define MX_BT455_OFFSET 0x100000
170 #define MX_BT431_OFFSET 0x180000
171 #define MX_IREQ_OFFSET 0x080000 /* Interrupt req. control */
172
173 int mfbmatch __P((struct device *, struct cfdata *, void *));
174 void mfbattach __P((struct device *, struct device *, void *));
175
176 struct cfattach mfb_ca = {
177 sizeof(struct mfb_softc), mfbmatch, mfbattach,
178 };
179
180 void mfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
181 struct fb_devconfig mfb_console_dc;
182 tc_addr_t mfb_consaddr;
183
184 struct wsdisplay_emulops mfb_emulops = {
185 rcons_cursor, /* could use hardware cursor; punt */
186 rcons_mapchar,
187 rcons_putchar,
188 rcons_copycols,
189 rcons_erasecols,
190 rcons_copyrows,
191 rcons_eraserows,
192 rcons_alloc_attr
193 };
194
195 struct wsscreen_descr mfb_stdscreen = {
196 "std", 0, 0,
197 &mfb_emulops,
198 0, 0,
199 0
200 };
201
202 const struct wsscreen_descr *_mfb_scrlist[] = {
203 &mfb_stdscreen,
204 };
205
206 struct wsscreen_list mfb_screenlist = {
207 sizeof(_mfb_scrlist) / sizeof(struct wsscreen_descr *), _mfb_scrlist
208 };
209
210 int mfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
211 int mfbmmap __P((void *, off_t, int));
212
213 int mfb_alloc_screen __P((void *, const struct wsscreen_descr *,
214 void **, int *, int *, long *));
215 void mfb_free_screen __P((void *, void *));
216 void mfb_show_screen __P((void *, void *));
217 int mfb_load_font __P((void *, void *, int, int, int, void *));
218
219 struct wsdisplay_accessops mfb_accessops = {
220 mfbioctl,
221 mfbmmap,
222 mfb_alloc_screen,
223 mfb_free_screen,
224 mfb_show_screen,
225 mfb_load_font
226 };
227
228 int mfb_cnattach __P((tc_addr_t));
229 int mfbintr __P((void *));
230 void mfbinit __P((struct fb_devconfig *));
231
232 static int set_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *));
233 static int get_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *));
234 static void set_curpos __P((struct mfb_softc *, struct wsdisplay_curpos *));
235 void bt431_set_curpos __P((struct mfb_softc *));
236
237 #define TWIN_LO(x) (twin = (x) & 0x00ff, twin << 8 | twin)
238 #define TWIN_HI(x) (twin = (x) & 0xff00, twin | twin >> 8)
239
240 /* XXX XXX XXX */
241 #define BT431_SELECT(curs, regno) do { \
242 u_int16_t twin; \
243 curs->bt_lo = TWIN_LO(regno); \
244 curs->bt_hi = TWIN_HI(regno); \
245 tc_wmb(); \
246 } while (0)
247
248 #define BT455_SELECT(vdac, index) do { \
249 vdac->bt_reg = index; \
250 vdac->bt_clr = 0; \
251 tc_wmb(); \
252 } while (0)
253 /* XXX XXX XXX */
254
255 /* bit order reverse */
256 const static u_int8_t flip[256] = {
257 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
258 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
259 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
260 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
261 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
262 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
263 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
264 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
265 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
266 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
267 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
268 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
269 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
270 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
271 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
272 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
273 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
274 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
275 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
276 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
277 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
278 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
279 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
280 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
281 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
282 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
283 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
284 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
285 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
286 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
287 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
288 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
289 };
290
291 int
292 mfbmatch(parent, match, aux)
293 struct device *parent;
294 struct cfdata *match;
295 void *aux;
296 {
297 struct tc_attach_args *ta = aux;
298
299 if (strncmp("PMAG-AA ", ta->ta_modname, TC_ROM_LLEN) != 0)
300 return (0);
301
302 return (1);
303 }
304
305 void
306 mfb_getdevconfig(dense_addr, dc)
307 tc_addr_t dense_addr;
308 struct fb_devconfig *dc;
309 {
310 struct raster *rap;
311 struct rcons *rcp;
312 int i;
313
314 dc->dc_vaddr = dense_addr;
315 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + MX_FB_OFFSET);
316
317 dc->dc_wid = 1280;
318 dc->dc_ht = 1024;
319 dc->dc_depth = 1;
320 dc->dc_rowbytes = 2048 / 8;
321 dc->dc_videobase = dc->dc_vaddr + MX_FB_OFFSET;
322 dc->dc_blanked = 0;
323
324 /* initialize colormap and cursor resource */
325 mfbinit(dc);
326
327 /* clear the screen */
328 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
329 *(u_int32_t *)(dc->dc_videobase + i) = 0;
330
331 /* initialize the raster */
332 rap = &dc->dc_raster;
333 rap->width = dc->dc_wid;
334 rap->height = dc->dc_ht;
335 rap->depth = dc->dc_depth;
336 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
337 rap->pixels = (u_int32_t *)dc->dc_videobase;
338
339 /* initialize the raster console blitter */
340 rcp = &dc->dc_rcons;
341 rcp->rc_sp = rap;
342 rcp->rc_crow = rcp->rc_ccol = -1;
343 rcp->rc_crowp = &rcp->rc_crow;
344 rcp->rc_ccolp = &rcp->rc_ccol;
345 rcons_init(rcp, 34, 80);
346
347 mfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
348 mfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
349 }
350
351 void
352 mfbattach(parent, self, aux)
353 struct device *parent, *self;
354 void *aux;
355 {
356 struct mfb_softc *sc = (struct mfb_softc *)self;
357 struct tc_attach_args *ta = aux;
358 struct wsemuldisplaydev_attach_args waa;
359 caddr_t mfbbase;
360 int console;
361 volatile register int junk;
362
363 console = (ta->ta_addr == mfb_consaddr);
364 if (console) {
365 sc->sc_dc = &mfb_console_dc;
366 sc->nscreens = 1;
367 }
368 else {
369 sc->sc_dc = (struct fb_devconfig *)
370 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
371 mfb_getdevconfig(ta->ta_addr, sc->sc_dc);
372 }
373 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
374 sc->sc_dc->dc_depth);
375 sc->magic_x = MX_MAGIC_X;
376 sc->magic_y = MX_MAGIC_Y;
377
378 tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, mfbintr, sc);
379
380 mfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
381 *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 0;
382 junk = *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET);
383 *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 1;
384
385 waa.console = console;
386 waa.scrdata = &mfb_screenlist;
387 waa.accessops = &mfb_accessops;
388 waa.accesscookie = sc;
389
390 config_found(self, &waa, wsemuldisplaydevprint);
391 }
392
393 int
394 mfbioctl(v, cmd, data, flag, p)
395 void *v;
396 u_long cmd;
397 caddr_t data;
398 int flag;
399 struct proc *p;
400 {
401 struct mfb_softc *sc = v;
402 struct fb_devconfig *dc = sc->sc_dc;
403 int turnoff;
404
405 switch (cmd) {
406 case WSDISPLAYIO_GTYPE:
407 *(u_int *)data = WSDISPLAY_TYPE_MFB;
408 return (0);
409
410 case WSDISPLAYIO_GINFO:
411 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
412 wsd_fbip->height = sc->sc_dc->dc_ht;
413 wsd_fbip->width = sc->sc_dc->dc_wid;
414 wsd_fbip->depth = sc->sc_dc->dc_depth;
415 wsd_fbip->cmsize = 0;
416 #undef fbt
417 return (0);
418
419 case WSDISPLAYIO_GETCMAP:
420 case WSDISPLAYIO_PUTCMAP:
421 return (ENOTTY);
422
423 case WSDISPLAYIO_SVIDEO:
424 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
425 if ((dc->dc_blanked == 0) ^ turnoff) {
426 dc->dc_blanked = turnoff;
427 /* XXX later XXX */
428 }
429 return (0);
430
431 case WSDISPLAYIO_GVIDEO:
432 *(u_int *)data = dc->dc_blanked ?
433 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
434 return (0);
435
436 case WSDISPLAYIO_GCURPOS:
437 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
438 return (0);
439
440 case WSDISPLAYIO_SCURPOS:
441 set_curpos(sc, (struct wsdisplay_curpos *)data);
442 bt431_set_curpos(sc);
443 return (0);
444
445 case WSDISPLAYIO_GCURMAX:
446 ((struct wsdisplay_curpos *)data)->x =
447 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
448 return (0);
449
450 case WSDISPLAYIO_GCURSOR:
451 return get_cursor(sc, (struct wsdisplay_cursor *)data);
452
453 case WSDISPLAYIO_SCURSOR:
454 return set_cursor(sc, (struct wsdisplay_cursor *)data);
455 }
456 return ENOTTY;
457 }
458
459 int
460 mfbmmap(v, offset, prot)
461 void *v;
462 off_t offset;
463 int prot;
464 {
465 struct mfb_softc *sc = v;
466
467 if (offset > MX_FB_SIZE)
468 return (-1);
469 return machine_btop(sc->sc_dc->dc_paddr + offset);
470 }
471
472 int
473 mfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
474 void *v;
475 const struct wsscreen_descr *type;
476 void **cookiep;
477 int *curxp, *curyp;
478 long *attrp;
479 {
480 struct mfb_softc *sc = v;
481 long defattr;
482
483 if (sc->nscreens > 0)
484 return (ENOMEM);
485
486 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
487 *curxp = 0;
488 *curyp = 0;
489 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
490 *attrp = defattr;
491 sc->nscreens++;
492 return (0);
493 }
494
495 void
496 mfb_free_screen(v, cookie)
497 void *v;
498 void *cookie;
499 {
500 struct mfb_softc *sc = v;
501
502 if (sc->sc_dc == &mfb_console_dc)
503 panic("mfb_free_screen: console");
504
505 sc->nscreens--;
506 }
507
508 void
509 mfb_show_screen(v, cookie)
510 void *v;
511 void *cookie;
512 {
513 }
514
515 int
516 mfb_load_font(v, cookie, first, num, stride, data)
517 void *v;
518 void *cookie;
519 int first, num, stride;
520 void *data;
521 {
522 return (EINVAL);
523 }
524
525 int
526 mfb_cnattach(addr)
527 tc_addr_t addr;
528 {
529 struct fb_devconfig *dcp = &mfb_console_dc;
530 long defattr;
531
532 mfb_getdevconfig(addr, dcp);
533
534 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
535
536 wsdisplay_cnattach(&mfb_stdscreen, &dcp->dc_rcons,
537 0, 0, defattr);
538 mfb_consaddr = addr;
539 return(0);
540 }
541
542
543 int
544 mfbintr(arg)
545 void *arg;
546 {
547 struct mfb_softc *sc = arg;
548 caddr_t mfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
549 struct bt455reg *vdac;
550 struct bt431reg *curs;
551 int v;
552 volatile register int junk;
553
554 junk = *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET);
555 /* *(u_int8_t *)(mfbbase + MX_IREQ_OFFSET) = 1; */
556
557 if (sc->sc_changed == 0)
558 return (1);
559
560 vdac = (void *)(mfbbase + MX_BT455_OFFSET);
561 curs = (void *)(mfbbase + MX_BT431_OFFSET);
562
563 v = sc->sc_changed;
564 sc->sc_changed = 0;
565 if (v & DATA_ENB_CHANGED) {
566 BT431_SELECT(curs, BT431_REG_COMMAND);
567 curs->bt_ctl = (sc->sc_curenb) ? 0x4444 : 0x0404;
568 }
569 if (v & DATA_CURSHAPE_CHANGED) {
570 #if 0
571 u_int8_t *bp1, *bp2;
572 u_int16_t twin;
573 int index;
574
575 bp1 = (u_int8_t *)&sc->sc_cursor.cc_image;
576 bp2 = (u_int8_t *)(&sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
577
578 BT431_SELECT(curs, BT431_REG_CRAM_BASE+0);
579 for (index = 0;
580 index < sizeof(sc->sc_cursor.cc_image)/sizeof(u_int16_t);
581 index++) {
582 twin = *bp1++ | (*bp2++ << 8);
583 curs->bt_ram = twin;
584 tc_wmb();
585 }
586 #else
587 u_int8_t *ip, *mp, img, msk;
588 int bcnt;
589
590 ip = (u_int8_t *)sc->sc_cursor.cc_image;
591 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
592
593 bcnt = 0;
594 BT431_SELECT(curs, BT431_REG_CRAM_BASE+0);
595 /* 64 pixel scan line is consisted with 16 byte cursor ram */
596 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
597 /* pad right half 32 pixel when smaller than 33 */
598 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
599 curs->bt_ram = 0;
600 tc_wmb();
601 }
602 else {
603 img = *ip++;
604 msk = *mp++;
605 img &= msk; /* cookie off image */
606 curs->bt_ram = (flip[msk] << 8) | flip[img];
607 tc_wmb();
608 }
609 bcnt += 2;
610 }
611 /* pad unoccupied scan lines */
612 while (bcnt < CURSOR_MAX_SIZE * 16) {
613 curs->bt_ram = 0;
614 tc_wmb();
615 bcnt += 2;
616 }
617 #endif
618 }
619 return (1);
620 }
621
622 void
623 mfbinit(dc)
624 struct fb_devconfig *dc;
625 {
626 caddr_t mfbbase = (caddr_t)dc->dc_vaddr;
627 struct bt431reg *curs = (void *)(mfbbase + MX_BT431_OFFSET);
628 struct bt455reg *vdac = (void *)(mfbbase + MX_BT455_OFFSET);
629 int i;
630
631 BT431_SELECT(curs, BT431_REG_COMMAND);
632 curs->bt_ctl = 0x0404; tc_wmb();
633 curs->bt_ctl = 0; tc_wmb();
634 curs->bt_ctl = 0; tc_wmb();
635 curs->bt_ctl = 0; tc_wmb();
636 curs->bt_ctl = 0; tc_wmb();
637 curs->bt_ctl = 0; tc_wmb();
638 curs->bt_ctl = 0; tc_wmb();
639 curs->bt_ctl = 0; tc_wmb();
640 curs->bt_ctl = 0; tc_wmb();
641 curs->bt_ctl = 0; tc_wmb();
642 curs->bt_ctl = 0; tc_wmb();
643 curs->bt_ctl = 0; tc_wmb();
644 curs->bt_ctl = 0; tc_wmb();
645
646 BT455_SELECT(vdac, 0);
647 for (i = 0; i < 16; i++) {
648 vdac->bt_cmap = 0; tc_wmb();
649 vdac->bt_cmap = 0; tc_wmb();
650 vdac->bt_cmap = 0; tc_wmb();
651 }
652
653 BT455_SELECT(vdac, 1);
654 vdac->bt_cmap = 0; tc_wmb();
655 vdac->bt_cmap = 0xff; tc_wmb();
656 vdac->bt_cmap = 0; tc_wmb();
657
658 BT455_SELECT(vdac, 8);
659 vdac->bt_cmap = 0; tc_wmb();
660 vdac->bt_cmap = 0xff; tc_wmb();
661 vdac->bt_cmap = 0; tc_wmb();
662
663 vdac->bt_ovly = 0; tc_wmb();
664 vdac->bt_ovly = 0xff; tc_wmb();
665 vdac->bt_ovly = 0; tc_wmb();
666 }
667
668 static int
669 set_cursor(sc, p)
670 struct mfb_softc *sc;
671 struct wsdisplay_cursor *p;
672 {
673 #define cc (&sc->sc_cursor)
674 int v, count;
675
676 v = p->which;
677 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
678 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
679 return (EINVAL);
680 count = ((p->size.x < 33) ? 4 : 8) * p->size.y;
681 if (!useracc(p->image, count, B_READ) ||
682 !useracc(p->mask, count, B_READ))
683 return (EFAULT);
684 }
685 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
686 if (v & WSDISPLAY_CURSOR_DOCUR)
687 cc->cc_hot = p->hot;
688 if (v & WSDISPLAY_CURSOR_DOPOS)
689 set_curpos(sc, &p->pos);
690 bt431_set_curpos(sc);
691 }
692
693 sc->sc_changed = 0;
694 if (v & WSDISPLAY_CURSOR_DOCUR) {
695 sc->sc_curenb = p->enable;
696 sc->sc_changed |= DATA_ENB_CHANGED;
697 }
698 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
699 cc->cc_size = p->size;
700 memset(cc->cc_image, 0, sizeof cc->cc_image);
701 copyin(p->image, cc->cc_image, count);
702 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count);
703 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
704 }
705
706 return (0);
707 #undef cc
708 }
709
710 static int
711 get_cursor(sc, p)
712 struct mfb_softc *sc;
713 struct wsdisplay_cursor *p;
714 {
715 return (ENOTTY); /* XXX */
716 }
717
718 static void
719 set_curpos(sc, curpos)
720 struct mfb_softc *sc;
721 struct wsdisplay_curpos *curpos;
722 {
723 struct fb_devconfig *dc = sc->sc_dc;
724 int x = curpos->x, y = curpos->y;
725
726 if (y < 0)
727 y = 0;
728 else if (y > dc->dc_ht)
729 y = dc->dc_ht;
730 if (x < 0)
731 x = 0;
732 else if (x > dc->dc_wid)
733 x = dc->dc_wid;
734 sc->sc_cursor.cc_pos.x = x;
735 sc->sc_cursor.cc_pos.y = y;
736 }
737
738 void
739 bt431_set_curpos(sc)
740 struct mfb_softc *sc;
741 {
742 caddr_t mfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
743 struct bt431reg *curs = (void *)(mfbbase + MX_BT431_OFFSET);
744 u_int16_t twin;
745 int x, y, s;
746
747 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
748 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
749 x += sc->magic_x; y += sc->magic_y; /* magic offset of MX coordinate */
750
751 s = spltty();
752
753 BT431_SELECT(curs, BT431_REG_CURSOR_X_LOW);
754 curs->bt_ctl = TWIN_LO(x); tc_wmb();
755 curs->bt_ctl = TWIN_HI(x); tc_wmb();
756 curs->bt_ctl = TWIN_LO(y); tc_wmb();
757 curs->bt_ctl = TWIN_HI(y); tc_wmb();
758
759 splx(s);
760 }
761