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