1 /* $NetBSD: mfb.c,v 1.64 2021/12/06 16:00:07 abs Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mfb.c,v 1.64 2021/12/06 16:00:07 abs Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
39 #include <sys/malloc.h>
40 #include <sys/buf.h>
41 #include <sys/ioctl.h>
42
43 #include <sys/bus.h>
44 #include <sys/intr.h>
45
46 #include <dev/wscons/wsconsio.h>
47 #include <dev/wscons/wsdisplayvar.h>
48
49 #include <dev/rasops/rasops.h>
50 #include <dev/wsfont/wsfont.h>
51
52 #include <dev/tc/tcvar.h>
53 #include <dev/ic/bt431reg.h>
54
55 #if defined(pmax)
56 #define machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
57 #endif
58
59 #if defined(alpha)
60 #define machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
61 #endif
62
63 /* Bt455 hardware registers, memory-mapped in 32bit stride */
64 #define bt_reg 0x0
65 #define bt_cmap 0x4
66 #define bt_clr 0x8
67 #define bt_ovly 0xc
68
69 /* Bt431 hardware registers, memory-mapped in 32bit stride */
70 #define bt_lo 0x0
71 #define bt_hi 0x4
72 #define bt_ram 0x8
73 #define bt_ctl 0xc
74
75 #define REGWRITE32(p,i,v) do { \
76 *(volatile uint32_t *)((p) + (i)) = (v); tc_wmb(); \
77 } while (0)
78
79 #define SELECT455(p,r) do { \
80 REGWRITE32((p), bt_reg, (r)); \
81 REGWRITE32((p), bt_clr, 0); \
82 } while (0)
83
84 #define TWIN(x) ((x)|((x) << 8))
85 #define TWIN_LO(x) (twin = (x) & 0x00ff, twin << 8 | twin)
86 #define TWIN_HI(x) (twin = (x) & 0xff00, twin | twin >> 8)
87
88 #define SELECT431(p,r) do { \
89 REGWRITE32((p), bt_lo, TWIN(r)); \
90 REGWRITE32((p), bt_hi, 0); \
91 } while (0)
92
93 struct hwcursor64 {
94 struct wsdisplay_curpos cc_pos;
95 struct wsdisplay_curpos cc_hot;
96 struct wsdisplay_curpos cc_size;
97 struct wsdisplay_curpos cc_magic;
98 #define CURSOR_MAX_SIZE 64
99 uint8_t cc_color[6];
100 uint64_t cc_image[CURSOR_MAX_SIZE];
101 uint64_t cc_mask[CURSOR_MAX_SIZE];
102 };
103
104 struct mfb_softc {
105 vaddr_t sc_vaddr;
106 size_t sc_size;
107 struct rasops_info *sc_ri;
108 struct hwcursor64 sc_cursor; /* software copy of cursor */
109 int sc_blanked;
110 int sc_curenb; /* cursor sprite enabled */
111 int sc_changed; /* need update of hardware */
112 int nscreens;
113 };
114
115 #define MX_MAGIC_X 360
116 #define MX_MAGIC_Y 36
117
118 #define MX_FB_OFFSET 0x200000
119 #define MX_FB_SIZE 0x200000
120 #define MX_BT455_OFFSET 0x100000
121 #define MX_BT431_OFFSET 0x180000
122 #define MX_IREQ_OFFSET 0x080000 /* Interrupt req. control */
123
124 static int mfbmatch(device_t, cfdata_t, void *);
125 static void mfbattach(device_t, device_t, void *);
126
127 CFATTACH_DECL_NEW(mfb, sizeof(struct mfb_softc),
128 mfbmatch, mfbattach, NULL, NULL);
129
130 static void mfb_common_init(struct rasops_info *);
131 static struct rasops_info mfb_console_ri;
132 static tc_addr_t mfb_consaddr;
133
134 static struct wsscreen_descr mfb_stdscreen = {
135 "std", 0, 0,
136 0, /* textops */
137 0, 0,
138 WSSCREEN_REVERSE
139 };
140
141 static const struct wsscreen_descr *_mfb_scrlist[] = {
142 &mfb_stdscreen,
143 };
144
145 static const struct wsscreen_list mfb_screenlist = {
146 sizeof(_mfb_scrlist) / sizeof(struct wsscreen_descr *), _mfb_scrlist
147 };
148
149 static int mfbioctl(void *, void *, u_long, void *, int, struct lwp *);
150 static paddr_t mfbmmap(void *, void *, off_t, int);
151
152 static int mfb_alloc_screen(void *, const struct wsscreen_descr *,
153 void **, int *, int *, long *);
154 static void mfb_free_screen(void *, void *);
155 static int mfb_show_screen(void *, void *, int,
156 void (*) (void *, int, int), void *);
157
158 static const struct wsdisplay_accessops mfb_accessops = {
159 mfbioctl,
160 mfbmmap,
161 mfb_alloc_screen,
162 mfb_free_screen,
163 mfb_show_screen,
164 0 /* load_font */
165 };
166
167 int mfb_cnattach(tc_addr_t);
168 static int mfbintr(void *);
169 static void mfbhwinit(void *);
170
171 static int set_cursor(struct mfb_softc *, struct wsdisplay_cursor *);
172 static int get_cursor(struct mfb_softc *, struct wsdisplay_cursor *);
173 static void set_curpos(struct mfb_softc *, struct wsdisplay_curpos *);
174
175 /* bit order reverse */
176 static const uint8_t flip[256] = {
177 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
178 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
179 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
180 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
181 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
182 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
183 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
184 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
185 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
186 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
187 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
188 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
189 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
190 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
191 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
192 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
193 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
194 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
195 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
196 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
197 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
198 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
199 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
200 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
201 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
202 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
203 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
204 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
205 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
206 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
207 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
208 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
209 };
210
211 static int
mfbmatch(device_t parent,cfdata_t match,void * aux)212 mfbmatch(device_t parent, cfdata_t match, void *aux)
213 {
214 struct tc_attach_args *ta = aux;
215
216 if (strncmp("PMAG-AA ", ta->ta_modname, TC_ROM_LLEN) != 0)
217 return (0);
218
219 return (1);
220 }
221
222 static void
mfbattach(device_t parent,device_t self,void * aux)223 mfbattach(device_t parent, device_t self, void *aux)
224 {
225 struct mfb_softc *sc = device_private(self);
226 struct tc_attach_args *ta = aux;
227 struct rasops_info *ri;
228 struct wsemuldisplaydev_attach_args waa;
229 int console;
230 volatile register int junk;
231
232 console = (ta->ta_addr == mfb_consaddr);
233 if (console) {
234 sc->sc_ri = ri = &mfb_console_ri;
235 ri->ri_flg &= ~RI_NO_AUTO;
236 sc->nscreens = 1;
237 }
238 else {
239 ri = malloc(sizeof(struct rasops_info),
240 M_DEVBUF, M_WAITOK | M_ZERO);
241 ri->ri_hw = (void *)ta->ta_addr;
242 mfb_common_init(ri);
243 sc->sc_ri = ri;
244 }
245 printf(": %dx%d, 1bpp\n", ri->ri_width, ri->ri_height);
246
247 sc->sc_vaddr = ta->ta_addr;
248 sc->sc_cursor.cc_magic.x = MX_MAGIC_X;
249 sc->sc_cursor.cc_magic.y = MX_MAGIC_Y;
250 sc->sc_blanked = sc->sc_curenb = 0;
251
252 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, mfbintr, sc);
253
254 /* clear any pending interrupts */
255 *(uint8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET) = 0;
256 junk = *(uint8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET);
257 __USE(junk);
258 *(uint8_t *)((char *)ri->ri_hw + MX_IREQ_OFFSET) = 1;
259
260 waa.console = console;
261 waa.scrdata = &mfb_screenlist;
262 waa.accessops = &mfb_accessops;
263 waa.accesscookie = sc;
264
265 config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
266 }
267
268 static void
mfb_common_init(struct rasops_info * ri)269 mfb_common_init(struct rasops_info *ri)
270 {
271 char *base;
272 int cookie;
273
274 base = (void *)ri->ri_hw;
275
276 /* initialize colormap and cursor hardware */
277 mfbhwinit(base);
278
279 ri->ri_flg = RI_CENTER | RI_FORCEMONO;
280 if (ri == &mfb_console_ri)
281 ri->ri_flg |= RI_NO_AUTO;
282 ri->ri_depth = 8; /* !! watch out !! */
283 ri->ri_width = 1280;
284 ri->ri_height = 1024;
285 ri->ri_stride = 2048;
286 ri->ri_bits = base + MX_FB_OFFSET;
287
288 /* clear the screen */
289 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
290
291 wsfont_init();
292 /* prefer 12 pixel wide font */
293 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
294 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
295 if (cookie <= 0)
296 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
297 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
298 if (cookie <= 0) {
299 printf("mfb: font table is empty\n");
300 return;
301 }
302
303 if (wsfont_lock(cookie, &ri->ri_font)) {
304 printf("mfb: couldn't lock font\n");
305 return;
306 }
307 ri->ri_wsfcookie = cookie;
308
309 rasops_init(ri, 34, 80);
310
311 /* XXX shouldn't be global */
312 mfb_stdscreen.nrows = ri->ri_rows;
313 mfb_stdscreen.ncols = ri->ri_cols;
314 mfb_stdscreen.textops = &ri->ri_ops;
315 mfb_stdscreen.capabilities = ri->ri_caps;
316 }
317
318 static int
mfbioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)319 mfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
320 {
321 struct mfb_softc *sc = v;
322 struct rasops_info *ri = sc->sc_ri;
323 int turnoff, s;
324
325 switch (cmd) {
326 case WSDISPLAYIO_GTYPE:
327 *(u_int *)data = WSDISPLAY_TYPE_MFB;
328 return (0);
329
330 case WSDISPLAYIO_GET_FBINFO: {
331 struct wsdisplayio_fbinfo *fbi = data;
332 return wsdisplayio_get_fbinfo(sc->sc_ri, fbi);
333 }
334
335 case WSDISPLAYIO_GINFO:
336 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
337 wsd_fbip->height = ri->ri_height;
338 wsd_fbip->width = ri->ri_width;
339 wsd_fbip->depth = ri->ri_depth;
340 wsd_fbip->cmsize = 0;
341 #undef fbt
342 return (0);
343
344 case WSDISPLAYIO_GETCMAP:
345 case WSDISPLAYIO_PUTCMAP:
346 return (EPASSTHROUGH);
347
348 case WSDISPLAYIO_SVIDEO:
349 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
350 if (sc->sc_blanked != turnoff) {
351 sc->sc_blanked = turnoff;
352 #if 0 /* XXX later XXX */
353 To turn off,
354 - assign Bt455 cmap[1].green with value 0 (black),
355 - assign Bt431 register #0 with value 0x04 to hide sprite cursor.
356 #endif /* XXX XXX XXX */
357 }
358 return (0);
359
360 case WSDISPLAYIO_GVIDEO:
361 *(u_int *)data = sc->sc_blanked ?
362 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
363 return (0);
364
365 case WSDISPLAYIO_GCURPOS:
366 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
367 return (0);
368
369 case WSDISPLAYIO_SCURPOS:
370 s = spltty();
371 set_curpos(sc, (struct wsdisplay_curpos *)data);
372 sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
373 splx(s);
374 return (0);
375
376 case WSDISPLAYIO_GCURMAX:
377 ((struct wsdisplay_curpos *)data)->x =
378 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
379 return (0);
380
381 case WSDISPLAYIO_GCURSOR:
382 return get_cursor(sc, (struct wsdisplay_cursor *)data);
383
384 case WSDISPLAYIO_SCURSOR:
385 return set_cursor(sc, (struct wsdisplay_cursor *)data);
386
387 case WSDISPLAYIO_SMODE:
388 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
389 s = spltty();
390 sc->sc_curenb = 0;
391 sc->sc_blanked = 0;
392 sc->sc_changed |= WSDISPLAY_CURSOR_DOCUR;
393 splx(s);
394 }
395 return (0);
396 }
397 return (EPASSTHROUGH);
398 }
399
400 static paddr_t
mfbmmap(void * v,void * vs,off_t offset,int prot)401 mfbmmap(void *v, void *vs, off_t offset, int prot)
402 {
403 struct mfb_softc *sc = v;
404
405 if (offset >= MX_FB_SIZE || offset < 0)
406 return (-1);
407 return machine_btop(sc->sc_vaddr + MX_FB_OFFSET + offset);
408 }
409
410 static int
mfb_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,long * attrp)411 mfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
412 int *curxp, int *curyp, long *attrp)
413 {
414 struct mfb_softc *sc = v;
415 struct rasops_info *ri = sc->sc_ri;
416 long defattr;
417
418 if (sc->nscreens > 0)
419 return (ENOMEM);
420
421 *cookiep = ri; /* one and only for now */
422 *curxp = 0;
423 *curyp = 0;
424 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
425 *attrp = defattr;
426 sc->nscreens++;
427 return (0);
428 }
429
430 static void
mfb_free_screen(void * v,void * cookie)431 mfb_free_screen(void *v, void *cookie)
432 {
433 struct mfb_softc *sc = v;
434
435 if (sc->sc_ri == &mfb_console_ri)
436 panic("mfb_free_screen: console");
437
438 sc->nscreens--;
439 }
440
441 static int
mfb_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)442 mfb_show_screen(void *v, void *cookie, int waitok,
443 void (*cb)(void *, int, int), void *cbarg)
444 {
445
446 return (0);
447 }
448
449 /* EXPORT */ int
mfb_cnattach(tc_addr_t addr)450 mfb_cnattach(tc_addr_t addr)
451 {
452 struct rasops_info *ri;
453 long defattr;
454
455 ri = &mfb_console_ri;
456 ri->ri_hw = (void *)addr;
457 mfb_common_init(ri);
458 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
459 wsdisplay_cnattach(&mfb_stdscreen, ri, 0, 0, defattr);
460 mfb_consaddr = addr;
461 return (0);
462 }
463
464 static int
mfbintr(void * arg)465 mfbintr(void *arg)
466 {
467 struct mfb_softc *sc = arg;
468 char *base, *vdac, *curs;
469 int v;
470 volatile register int junk;
471
472 base = (void *)sc->sc_ri->ri_hw;
473 junk = *(uint8_t *)(base + MX_IREQ_OFFSET);
474 __USE(junk);
475 #if 0
476 *(uint8_t *)(base + MX_IREQ_OFFSET) = 0;
477 #endif
478 if (sc->sc_changed == 0)
479 return (1);
480
481 vdac = base + MX_BT455_OFFSET;
482 curs = base + MX_BT431_OFFSET;
483 v = sc->sc_changed;
484 if (v & WSDISPLAY_CURSOR_DOCUR) {
485 int onoff;
486
487 onoff = (sc->sc_curenb) ? 0x4444 : 0x0404;
488 SELECT431(curs, BT431_REG_COMMAND);
489 REGWRITE32(curs, bt_ctl, onoff);
490 }
491 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
492 int x, y;
493 uint32_t twin;
494
495 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
496 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
497
498 x += sc->sc_cursor.cc_magic.x;
499 y += sc->sc_cursor.cc_magic.y;
500
501 SELECT431(curs, BT431_REG_CURSOR_X_LOW);
502 REGWRITE32(curs, bt_ctl, TWIN_LO(x));
503 REGWRITE32(curs, bt_ctl, TWIN_HI(x));
504 REGWRITE32(curs, bt_ctl, TWIN_LO(y));
505 REGWRITE32(curs, bt_ctl, TWIN_HI(y));
506 }
507 if (v & WSDISPLAY_CURSOR_DOCMAP) {
508 uint8_t *cp = sc->sc_cursor.cc_color;
509
510 SELECT455(vdac, 8);
511 REGWRITE32(vdac, bt_cmap, 0);
512 REGWRITE32(vdac, bt_cmap, cp[1]);
513 REGWRITE32(vdac, bt_cmap, 0);
514
515 REGWRITE32(vdac, bt_cmap, 0);
516 REGWRITE32(vdac, bt_cmap, cp[1]);
517 REGWRITE32(vdac, bt_cmap, 0);
518
519 REGWRITE32(vdac, bt_ovly, 0);
520 REGWRITE32(vdac, bt_ovly, cp[0]);
521 REGWRITE32(vdac, bt_ovly, 0);
522 }
523 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
524 uint8_t *ip, *mp, img, msk;
525 int bcnt;
526
527 ip = (uint8_t *)sc->sc_cursor.cc_image;
528 mp = (uint8_t *)sc->sc_cursor.cc_mask;
529 bcnt = 0;
530 SELECT431(curs, BT431_REG_CRAM_BASE);
531
532 /* 64 pixel scan line is consisted with 16 byte cursor ram */
533 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
534 /* pad right half 32 pixel when smaller than 33 */
535 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
536 REGWRITE32(curs, bt_ram, 0);
537 }
538 else {
539 int half;
540
541 img = *ip++;
542 msk = *mp++;
543 img &= msk; /* cookie off image */
544 half = (flip[msk] << 8) | flip[img];
545 REGWRITE32(curs, bt_ram, half);
546 }
547 bcnt += 2;
548 }
549 /* pad unoccupied scan lines */
550 while (bcnt < CURSOR_MAX_SIZE * 16) {
551 REGWRITE32(curs, bt_ram, 0);
552 bcnt += 2;
553 }
554 }
555 sc->sc_changed = 0;
556 return (1);
557 }
558
559 static void
mfbhwinit(void * mfbbase)560 mfbhwinit(void *mfbbase)
561 {
562 char *vdac, *curs;
563 int i;
564
565 vdac = (char *)mfbbase + MX_BT455_OFFSET;
566 curs = (char *)mfbbase + MX_BT431_OFFSET;
567 SELECT431(curs, BT431_REG_COMMAND);
568 REGWRITE32(curs, bt_ctl, 0x0404);
569 REGWRITE32(curs, bt_ctl, 0); /* XLO */
570 REGWRITE32(curs, bt_ctl, 0); /* XHI */
571 REGWRITE32(curs, bt_ctl, 0); /* YLO */
572 REGWRITE32(curs, bt_ctl, 0); /* YHI */
573 REGWRITE32(curs, bt_ctl, 0); /* XWLO */
574 REGWRITE32(curs, bt_ctl, 0); /* XWHI */
575 REGWRITE32(curs, bt_ctl, 0); /* WYLO */
576 REGWRITE32(curs, bt_ctl, 0); /* WYLO */
577 REGWRITE32(curs, bt_ctl, 0); /* WWLO */
578 REGWRITE32(curs, bt_ctl, 0); /* WWHI */
579 REGWRITE32(curs, bt_ctl, 0); /* WHLO */
580 REGWRITE32(curs, bt_ctl, 0); /* WHHI */
581
582 /* 0: black, 1: white, 8,9: cursor mask, ovly: cursor image */
583 SELECT455(vdac, 0);
584 REGWRITE32(vdac, bt_cmap, 0);
585 REGWRITE32(vdac, bt_cmap, 0);
586 REGWRITE32(vdac, bt_cmap, 0);
587 REGWRITE32(vdac, bt_cmap, 0);
588 REGWRITE32(vdac, bt_cmap, 0xff);
589 REGWRITE32(vdac, bt_cmap, 0);
590 for (i = 2; i < 16; i++) {
591 REGWRITE32(vdac, bt_cmap, 0);
592 REGWRITE32(vdac, bt_cmap, 0);
593 REGWRITE32(vdac, bt_cmap, 0);
594 }
595 REGWRITE32(vdac, bt_ovly, 0);
596 REGWRITE32(vdac, bt_ovly, 0xff);
597 REGWRITE32(vdac, bt_ovly, 0);
598
599 SELECT431(curs, BT431_REG_CRAM_BASE);
600 for (i = 0; i < 512; i++) {
601 REGWRITE32(curs, bt_ram, 0);
602 }
603 }
604
605 static int
set_cursor(struct mfb_softc * sc,struct wsdisplay_cursor * p)606 set_cursor(struct mfb_softc *sc, struct wsdisplay_cursor *p)
607 {
608 #define cc (&sc->sc_cursor)
609 u_int v, count = 0, icount = 0, index = 0;
610 uint64_t image[CURSOR_MAX_SIZE];
611 uint64_t mask[CURSOR_MAX_SIZE];
612 uint8_t color[6];
613 int error, s;
614
615 v = p->which;
616 if (v & WSDISPLAY_CURSOR_DOCMAP) {
617 index = p->cmap.index;
618 count = p->cmap.count;
619 if (index >= 2 || count > 2 - index)
620 return (EINVAL);
621 error = copyin(p->cmap.red, &color[index], count);
622 if (error)
623 return error;
624 }
625 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
626 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
627 return (EINVAL);
628 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
629 error = copyin(p->image, image, icount);
630 if (error)
631 return error;
632 error = copyin(p->mask, mask, icount);
633 if (error)
634 return error;
635 }
636
637 s = spltty();
638 if (v & WSDISPLAY_CURSOR_DOCUR)
639 sc->sc_curenb = p->enable;
640 if (v & WSDISPLAY_CURSOR_DOPOS)
641 set_curpos(sc, &p->pos);
642 if (v & WSDISPLAY_CURSOR_DOHOT)
643 cc->cc_hot = p->hot;
644 if (v & WSDISPLAY_CURSOR_DOCMAP)
645 memcpy(&cc->cc_color[index], &color[index], count);
646 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
647 cc->cc_size = p->size;
648 memset(cc->cc_image, 0, sizeof cc->cc_image);
649 memcpy(cc->cc_image, image, icount);
650 memset(cc->cc_mask, 0, sizeof cc->cc_mask);
651 memcpy(cc->cc_mask, mask, icount);
652 }
653 sc->sc_changed |= v;
654 splx(s);
655
656 return (0);
657 #undef cc
658 }
659
660 static int
get_cursor(struct mfb_softc * sc,struct wsdisplay_cursor * p)661 get_cursor(struct mfb_softc *sc, struct wsdisplay_cursor *p)
662 {
663 return (EPASSTHROUGH); /* XXX */
664 }
665
666 static void
set_curpos(struct mfb_softc * sc,struct wsdisplay_curpos * curpos)667 set_curpos(struct mfb_softc *sc, struct wsdisplay_curpos *curpos)
668 {
669 struct rasops_info *ri = sc->sc_ri;
670 int x = curpos->x, y = curpos->y;
671
672 if (y < 0)
673 y = 0;
674 else if (y > ri->ri_height)
675 y = ri->ri_height;
676 if (x < 0)
677 x = 0;
678 else if (x > ri->ri_width)
679 x = ri->ri_width;
680 sc->sc_cursor.cc_pos.x = x;
681 sc->sc_cursor.cc_pos.y = y;
682 }
683