1 /* $NetBSD: xcfb.c,v 1.60 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: xcfb.c,v 1.60 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/tc/ioasicreg.h>
54 #include <dev/ic/ims332reg.h>
55 #include <pmax/pmax/maxine.h>
56
57 struct hwcmap256 {
58 #define CMAP_SIZE 256 /* 256 R/G/B entries */
59 uint8_t r[CMAP_SIZE];
60 uint8_t g[CMAP_SIZE];
61 uint8_t b[CMAP_SIZE];
62 };
63
64 struct hwcursor64 {
65 struct wsdisplay_curpos cc_pos;
66 struct wsdisplay_curpos cc_hot;
67 struct wsdisplay_curpos cc_size;
68 struct wsdisplay_curpos cc_magic; /* not used by PMAG-DV */
69 #define CURSOR_MAX_SIZE 64
70 uint8_t cc_color[6];
71 uint64_t cc_image[CURSOR_MAX_SIZE];
72 uint64_t cc_mask[CURSOR_MAX_SIZE];
73 };
74
75 #define XCFB_FB_BASE (XINE_PHYS_CFB_START + 0x2000000)
76 #define XCFB_FB_SIZE 0x100000
77
78 #define IMS332_HIGH (IOASIC_SLOT_5_START)
79 #define IMS332_RLOW (IOASIC_SLOT_7_START)
80 #define IMS332_WLOW (IOASIC_SLOT_7_START + 0x20000)
81
82 struct xcfb_softc {
83 vaddr_t sc_vaddr;
84 size_t sc_size;
85 struct rasops_info *sc_ri;
86 struct hwcmap256 sc_cmap; /* software copy of colormap */
87 struct hwcursor64 sc_cursor; /* software copy of cursor */
88 int sc_blanked;
89 /* XXX MAXINE can take PMAG-DV vertical retrace interrupt XXX */
90 int nscreens;
91 /* cursor coordinate is located at upper-left corner */
92 int sc_csr; /* software copy of IMS332 CSR A */
93 };
94
95 static int xcfbmatch(device_t, cfdata_t, void *);
96 static void xcfbattach(device_t, device_t, void *);
97
98 CFATTACH_DECL_NEW(xcfb, sizeof(struct xcfb_softc),
99 xcfbmatch, xcfbattach, NULL, NULL);
100
101 static tc_addr_t xcfb_consaddr;
102 static struct rasops_info xcfb_console_ri;
103 static void xcfb_common_init(struct rasops_info *);
104 static void xcfbhwinit(void *);
105 int xcfb_cnattach(void);
106
107 struct wsscreen_descr xcfb_stdscreen = {
108 "std", 0, 0,
109 0, /* textops */
110 0, 0,
111 WSSCREEN_REVERSE
112 };
113
114 static const struct wsscreen_descr *_xcfb_scrlist[] = {
115 &xcfb_stdscreen,
116 };
117
118 static const struct wsscreen_list xcfb_screenlist = {
119 sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist
120 };
121
122 static int xcfbioctl(void *, void *, u_long, void *, int, struct lwp *);
123 static paddr_t xcfbmmap(void *, void *, off_t, int);
124
125 static int xcfb_alloc_screen(void *, const struct wsscreen_descr *,
126 void **, int *, int *, long *);
127 static void xcfb_free_screen(void *, void *);
128 static int xcfb_show_screen(void *, void *, int,
129 void (*) (void *, int, int), void *);
130
131 static const struct wsdisplay_accessops xcfb_accessops = {
132 xcfbioctl,
133 xcfbmmap,
134 xcfb_alloc_screen,
135 xcfb_free_screen,
136 xcfb_show_screen,
137 0 /* load_font */
138 };
139
140 static int xcfbintr(void *);
141 static void xcfb_screenblank(struct xcfb_softc *);
142 static void xcfb_cmap_init(struct xcfb_softc *);
143 static int set_cmap(struct xcfb_softc *, struct wsdisplay_cmap *);
144 static int get_cmap(struct xcfb_softc *, struct wsdisplay_cmap *);
145 static int set_cursor(struct xcfb_softc *, struct wsdisplay_cursor *);
146 static int get_cursor(struct xcfb_softc *, struct wsdisplay_cursor *);
147 static void set_curpos(struct xcfb_softc *, struct wsdisplay_curpos *);
148 static void ims332_loadcmap(struct hwcmap256 *);
149 static void ims332_set_curpos(struct xcfb_softc *);
150 static void ims332_load_curcmap(struct xcfb_softc *);
151 static void ims332_load_curshape(struct xcfb_softc *);
152 static void ims332_write_reg(int, uint32_t);
153 #if 0
154 static uint32_t ims332_read_reg(int);
155 #endif
156
157 extern long ioasic_base; /* XXX */
158
159 /*
160 * Compose 2 bit/pixel cursor image.
161 * M M M M I I I I M I M I M I M I
162 * [ before ] [ after ]
163 * 3 2 1 0 3 2 1 0 3 3 2 2 1 1 0 0
164 * 7 6 5 4 7 6 5 4 7 7 6 6 5 5 4 4
165 */
166 static const uint8_t shuffle[256] = {
167 0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15,
168 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55,
169 0x02, 0x03, 0x06, 0x07, 0x12, 0x13, 0x16, 0x17,
170 0x42, 0x43, 0x46, 0x47, 0x52, 0x53, 0x56, 0x57,
171 0x08, 0x09, 0x0c, 0x0d, 0x18, 0x19, 0x1c, 0x1d,
172 0x48, 0x49, 0x4c, 0x4d, 0x58, 0x59, 0x5c, 0x5d,
173 0x0a, 0x0b, 0x0e, 0x0f, 0x1a, 0x1b, 0x1e, 0x1f,
174 0x4a, 0x4b, 0x4e, 0x4f, 0x5a, 0x5b, 0x5e, 0x5f,
175 0x20, 0x21, 0x24, 0x25, 0x30, 0x31, 0x34, 0x35,
176 0x60, 0x61, 0x64, 0x65, 0x70, 0x71, 0x74, 0x75,
177 0x22, 0x23, 0x26, 0x27, 0x32, 0x33, 0x36, 0x37,
178 0x62, 0x63, 0x66, 0x67, 0x72, 0x73, 0x76, 0x77,
179 0x28, 0x29, 0x2c, 0x2d, 0x38, 0x39, 0x3c, 0x3d,
180 0x68, 0x69, 0x6c, 0x6d, 0x78, 0x79, 0x7c, 0x7d,
181 0x2a, 0x2b, 0x2e, 0x2f, 0x3a, 0x3b, 0x3e, 0x3f,
182 0x6a, 0x6b, 0x6e, 0x6f, 0x7a, 0x7b, 0x7e, 0x7f,
183 0x80, 0x81, 0x84, 0x85, 0x90, 0x91, 0x94, 0x95,
184 0xc0, 0xc1, 0xc4, 0xc5, 0xd0, 0xd1, 0xd4, 0xd5,
185 0x82, 0x83, 0x86, 0x87, 0x92, 0x93, 0x96, 0x97,
186 0xc2, 0xc3, 0xc6, 0xc7, 0xd2, 0xd3, 0xd6, 0xd7,
187 0x88, 0x89, 0x8c, 0x8d, 0x98, 0x99, 0x9c, 0x9d,
188 0xc8, 0xc9, 0xcc, 0xcd, 0xd8, 0xd9, 0xdc, 0xdd,
189 0x8a, 0x8b, 0x8e, 0x8f, 0x9a, 0x9b, 0x9e, 0x9f,
190 0xca, 0xcb, 0xce, 0xcf, 0xda, 0xdb, 0xde, 0xdf,
191 0xa0, 0xa1, 0xa4, 0xa5, 0xb0, 0xb1, 0xb4, 0xb5,
192 0xe0, 0xe1, 0xe4, 0xe5, 0xf0, 0xf1, 0xf4, 0xf5,
193 0xa2, 0xa3, 0xa6, 0xa7, 0xb2, 0xb3, 0xb6, 0xb7,
194 0xe2, 0xe3, 0xe6, 0xe7, 0xf2, 0xf3, 0xf6, 0xf7,
195 0xa8, 0xa9, 0xac, 0xad, 0xb8, 0xb9, 0xbc, 0xbd,
196 0xe8, 0xe9, 0xec, 0xed, 0xf8, 0xf9, 0xfc, 0xfd,
197 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf,
198 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff,
199 };
200
201 static int
xcfbmatch(device_t parent,cfdata_t match,void * aux)202 xcfbmatch(device_t parent, cfdata_t match, void *aux)
203 {
204 struct tc_attach_args *ta = aux;
205
206 if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0)
207 return (0);
208
209 return (1);
210 }
211
212 static void
xcfbattach(device_t parent,device_t self,void * aux)213 xcfbattach(device_t parent, device_t self, void *aux)
214 {
215 struct xcfb_softc *sc = device_private(self);
216 struct tc_attach_args *ta = aux;
217 struct rasops_info *ri;
218 struct wsemuldisplaydev_attach_args waa;
219 int console;
220
221 console = (ta->ta_addr == xcfb_consaddr);
222 if (console) {
223 sc->sc_ri = ri = &xcfb_console_ri;
224 ri->ri_flg &= ~RI_NO_AUTO;
225 sc->nscreens = 1;
226 }
227 else {
228 ri = malloc(sizeof(struct rasops_info), M_DEVBUF, M_WAITOK | M_ZERO);
229 ri->ri_hw = (void *)ioasic_base;
230 xcfb_common_init(ri);
231 sc->sc_ri = ri;
232 }
233 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
234
235 xcfb_cmap_init(sc);
236
237 sc->sc_vaddr = ta->ta_addr;
238 sc->sc_blanked = 0;
239 sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
240
241 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc);
242
243 waa.console = console;
244 waa.scrdata = &xcfb_screenlist;
245 waa.accessops = &xcfb_accessops;
246 waa.accesscookie = sc;
247
248 config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE);
249 }
250
251 static void
xcfb_cmap_init(struct xcfb_softc * sc)252 xcfb_cmap_init(struct xcfb_softc *sc)
253 {
254 struct hwcmap256 *cm;
255 const uint8_t *p;
256 int index;
257
258 cm = &sc->sc_cmap;
259 p = rasops_cmap;
260 for (index = 0; index < CMAP_SIZE; index++, p += 3) {
261 cm->r[index] = p[0];
262 cm->g[index] = p[1];
263 cm->b[index] = p[2];
264 }
265 }
266
267 static void
xcfb_common_init(struct rasops_info * ri)268 xcfb_common_init(struct rasops_info *ri)
269 {
270 int cookie;
271
272 /* initialize colormap and cursor hardware */
273 xcfbhwinit((void *)ri->ri_hw);
274
275 ri->ri_flg = RI_CENTER;
276 if (ri == &xcfb_console_ri)
277 ri->ri_flg |= RI_NO_AUTO;
278 ri->ri_depth = 8;
279 ri->ri_width = 1024;
280 ri->ri_height = 768;
281 ri->ri_stride = 1024;
282 ri->ri_bits = (void *)MIPS_PHYS_TO_KSEG1(XCFB_FB_BASE);
283
284 /* clear the screen */
285 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
286
287 wsfont_init();
288 /* prefer 12 pixel wide font */
289 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
290 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
291 if (cookie <= 0)
292 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
293 WSDISPLAY_FONTORDER_L2R, WSFONT_FIND_BITMAP);
294 if (cookie <= 0) {
295 printf("xcfb: font table is empty\n");
296 return;
297 }
298
299 if (wsfont_lock(cookie, &ri->ri_font)) {
300 printf("xcfb: couldn't lock font\n");
301 return;
302 }
303 ri->ri_wsfcookie = cookie;
304
305 rasops_init(ri, 34, 80);
306
307 /* XXX shouldn't be global */
308 xcfb_stdscreen.nrows = ri->ri_rows;
309 xcfb_stdscreen.ncols = ri->ri_cols;
310 xcfb_stdscreen.textops = &ri->ri_ops;
311 xcfb_stdscreen.capabilities = ri->ri_caps;
312 }
313
314 int
xcfb_cnattach(void)315 xcfb_cnattach(void)
316 {
317 struct rasops_info *ri;
318 long defattr;
319
320 ri = &xcfb_console_ri;
321 ri->ri_hw = (void *)ioasic_base;
322 xcfb_common_init(ri);
323 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
324 wsdisplay_cnattach(&xcfb_stdscreen, ri, 0, 0, defattr);
325 xcfb_consaddr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START);
326 return (0);
327 }
328
329 static void
xcfbhwinit(void * base)330 xcfbhwinit(void *base)
331 {
332 volatile uint32_t *csr;
333 uint32_t i;
334 const uint8_t *p;
335
336 csr = (volatile uint32_t *)((char *)base + IOASIC_CSR);
337 i = *csr;
338 i &= ~XINE_CSR_VDAC_ENABLE;
339 *csr = i;
340 DELAY(50);
341 i |= XINE_CSR_VDAC_ENABLE;
342 *csr = i;
343 DELAY(50);
344 ims332_write_reg(IMS332_REG_BOOT, 0x2c);
345 ims332_write_reg(IMS332_REG_CSR_A,
346 IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
347 ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
348 ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
349 ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
350 ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
351 ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
352 ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
353 ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
354 ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
355 ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
356 ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
357 ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
358 ims332_write_reg(IMS332_REG_LINE_START, 0x10);
359 ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
360 ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
361 ims332_write_reg(IMS332_REG_CSR_A,
362 IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
363
364 /* build sane colormap */
365 p = rasops_cmap;
366 for (i = 0; i < CMAP_SIZE; i++, p += 3) {
367 uint32_t bgr;
368
369 bgr = p[2] << 16 | p[1] << 8 | p[0];
370 ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr);
371 }
372
373 /* clear out cursor image */
374 for (i = 0; i < 512; i++)
375 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
376
377 /*
378 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
379 * cursor image. LUT_1 for mask color, while LUT_2 for
380 * image color. LUT_0 will be never used.
381 */
382 ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
383 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
384 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
385 }
386
387 static int
xcfbioctl(void * v,void * vs,u_long cmd,void * data,int flag,struct lwp * l)388 xcfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
389 {
390 struct xcfb_softc *sc = v;
391 struct rasops_info *ri = sc->sc_ri;
392 int turnoff, error;
393
394 switch (cmd) {
395 case WSDISPLAYIO_GTYPE:
396 *(u_int *)data = WSDISPLAY_TYPE_XCFB;
397 return (0);
398
399 case WSDISPLAYIO_GET_FBINFO: {
400 struct wsdisplayio_fbinfo *fbi = data;
401 return wsdisplayio_get_fbinfo(sc->sc_ri, fbi);
402 }
403
404 case WSDISPLAYIO_GINFO:
405 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
406 wsd_fbip->height = ri->ri_height;
407 wsd_fbip->width = ri->ri_width;
408 wsd_fbip->depth = ri->ri_depth;
409 wsd_fbip->cmsize = CMAP_SIZE;
410 #undef fbt
411 return (0);
412
413 case WSDISPLAYIO_GETCMAP:
414 return get_cmap(sc, (struct wsdisplay_cmap *)data);
415
416 case WSDISPLAYIO_PUTCMAP:
417 error = set_cmap(sc, (struct wsdisplay_cmap *)data);
418 if (error == 0)
419 ims332_loadcmap(&sc->sc_cmap);
420 return (error);
421
422 case WSDISPLAYIO_SVIDEO:
423 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
424 if (sc->sc_blanked != turnoff) {
425 sc->sc_blanked = turnoff;
426 xcfb_screenblank(sc);
427 }
428 return (0);
429
430 case WSDISPLAYIO_GVIDEO:
431 *(u_int *)data = sc->sc_blanked ?
432 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
433 return (0);
434
435 case WSDISPLAYIO_GCURPOS:
436 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
437 return (0);
438
439 case WSDISPLAYIO_SCURPOS:
440 set_curpos(sc, (struct wsdisplay_curpos *)data);
441 ims332_set_curpos(sc);
442 return (0);
443
444 case WSDISPLAYIO_GCURMAX:
445 ((struct wsdisplay_curpos *)data)->x =
446 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
447 return (0);
448
449 case WSDISPLAYIO_GCURSOR:
450 return get_cursor(sc, (struct wsdisplay_cursor *)data);
451
452 case WSDISPLAYIO_SCURSOR:
453 return set_cursor(sc, (struct wsdisplay_cursor *)data);
454
455 case WSDISPLAYIO_SMODE:
456 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
457 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
458 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
459 xcfb_cmap_init(sc);
460 ims332_loadcmap(&sc->sc_cmap);
461 sc->sc_blanked = 0;
462 xcfb_screenblank(sc);
463 }
464 return (0);
465 }
466 return (EPASSTHROUGH);
467 }
468
469 static paddr_t
xcfbmmap(void * v,void * vs,off_t offset,int prot)470 xcfbmmap(void *v, void *vs, off_t offset, int prot)
471 {
472
473 if (offset >= XCFB_FB_SIZE || offset < 0)
474 return (-1);
475 return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset));
476 }
477
478 static int
xcfb_alloc_screen(void * v,const struct wsscreen_descr * type,void ** cookiep,int * curxp,int * curyp,long * attrp)479 xcfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
480 int *curxp, int *curyp, long *attrp)
481 {
482 struct xcfb_softc *sc = v;
483 struct rasops_info *ri = sc->sc_ri;
484 long defattr;
485
486 if (sc->nscreens > 0)
487 return (ENOMEM);
488
489 *cookiep = ri; /* one and only for now */
490 *curxp = 0;
491 *curyp = 0;
492 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
493 *attrp = defattr;
494 sc->nscreens++;
495 return (0);
496 }
497
498 static void
xcfb_free_screen(void * v,void * cookie)499 xcfb_free_screen(void *v, void *cookie)
500 {
501 struct xcfb_softc *sc = v;
502
503 if (sc->sc_ri == &xcfb_console_ri)
504 panic("xcfb_free_screen: console");
505
506 sc->nscreens--;
507 }
508
509 static int
xcfb_show_screen(void * v,void * cookie,int waitok,void (* cb)(void *,int,int),void * cbarg)510 xcfb_show_screen(void *v, void *cookie, int waitok,
511 void (*cb)(void *, int, int), void *cbarg)
512 {
513
514 return (0);
515 }
516
517 static int
xcfbintr(void * v)518 xcfbintr(void *v)
519 {
520 struct xcfb_softc *sc = v;
521 uint32_t *intr, i;
522
523 intr = (uint32_t *)((char *)sc->sc_ri->ri_hw + IOASIC_INTR);
524 i = *intr;
525 i &= ~XINE_INTR_VINT;
526 *intr = i;
527 return (1);
528 }
529
530 static void
xcfb_screenblank(struct xcfb_softc * sc)531 xcfb_screenblank(struct xcfb_softc *sc)
532 {
533 if (sc->sc_blanked)
534 sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK;
535 else
536 sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK;
537 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
538 }
539
540 static int
get_cmap(struct xcfb_softc * sc,struct wsdisplay_cmap * p)541 get_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p)
542 {
543 u_int index = p->index, count = p->count;
544 int error;
545
546 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
547 return (EINVAL);
548
549 error = copyout(&sc->sc_cmap.r[index], p->red, count);
550 if (error)
551 return error;
552 error = copyout(&sc->sc_cmap.g[index], p->green, count);
553 if (error)
554 return error;
555 error = copyout(&sc->sc_cmap.b[index], p->blue, count);
556 return error;
557 }
558
559 static int
set_cmap(struct xcfb_softc * sc,struct wsdisplay_cmap * p)560 set_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p)
561 {
562 struct hwcmap256 cmap;
563 u_int index = p->index, count = p->count;
564 int error;
565
566 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
567 return (EINVAL);
568
569 error = copyin(p->red, &cmap.r[index], count);
570 if (error)
571 return error;
572 error = copyin(p->green, &cmap.g[index], count);
573 if (error)
574 return error;
575 error = copyin(p->blue, &cmap.b[index], count);
576 if (error)
577 return error;
578 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
579 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
580 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
581 return (0);
582 }
583
584 static int
set_cursor(struct xcfb_softc * sc,struct wsdisplay_cursor * p)585 set_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p)
586 {
587 #define cc (&sc->sc_cursor)
588 u_int v, index = 0, count = 0, icount = 0;
589 uint8_t r[2], g[2], b[2], image[512], mask[512];
590 int error;
591
592 v = p->which;
593 if (v & WSDISPLAY_CURSOR_DOCMAP) {
594 index = p->cmap.index;
595 count = p->cmap.count;
596
597 if (index >= 2 || count > 2 - index)
598 return (EINVAL);
599 error = copyin(p->cmap.red, &r[index], count);
600 if (error)
601 return error;
602 error = copyin(p->cmap.green, &g[index], count);
603 if (error)
604 return error;
605 error = copyin(p->cmap.blue, &b[index], count);
606 if (error)
607 return error;
608 }
609 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
610 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
611 return (EINVAL);
612 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
613 error = copyin(p->image, image, icount);
614 if (error)
615 return error;
616 error = copyin(p->mask, mask, icount);
617 if (error)
618 return error;
619 }
620
621 if (v & WSDISPLAY_CURSOR_DOCMAP) {
622 memcpy(&cc->cc_color[index], &r[index], count);
623 memcpy(&cc->cc_color[index + 2], &g[index], count);
624 memcpy(&cc->cc_color[index + 4], &b[index], count);
625 ims332_load_curcmap(sc);
626 }
627 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
628 cc->cc_size = p->size;
629 memset(cc->cc_image, 0, sizeof cc->cc_image);
630 memcpy(cc->cc_image, image, icount);
631 memset(cc->cc_mask, 0, sizeof cc->cc_mask);
632 memcpy(cc->cc_mask, mask, icount);
633 ims332_load_curshape(sc);
634 }
635 if (v & WSDISPLAY_CURSOR_DOCUR) {
636 cc->cc_hot = p->hot;
637 if (p->enable)
638 sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
639 else
640 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
641 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
642 }
643 if (v & WSDISPLAY_CURSOR_DOPOS) {
644 set_curpos(sc, &p->pos);
645 ims332_set_curpos(sc);
646 }
647
648 return (0);
649 #undef cc
650 }
651
652 static int
get_cursor(struct xcfb_softc * sc,struct wsdisplay_cursor * p)653 get_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p)
654 {
655 return (EPASSTHROUGH); /* XXX */
656 }
657
658 static void
set_curpos(struct xcfb_softc * sc,struct wsdisplay_curpos * curpos)659 set_curpos(struct xcfb_softc *sc, struct wsdisplay_curpos *curpos)
660 {
661 struct rasops_info *ri = sc->sc_ri;
662 int x = curpos->x, y = curpos->y;
663
664 if (y < 0)
665 y = 0;
666 else if (y > ri->ri_height)
667 y = ri->ri_height;
668 if (x < 0)
669 x = 0;
670 else if (x > ri->ri_width)
671 x = ri->ri_width;
672 sc->sc_cursor.cc_pos.x = x;
673 sc->sc_cursor.cc_pos.y = y;
674 }
675
676 static void
ims332_loadcmap(struct hwcmap256 * cm)677 ims332_loadcmap(struct hwcmap256 *cm)
678 {
679 int i;
680 uint32_t rgb;
681
682 for (i = 0; i < CMAP_SIZE; i++) {
683 rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
684 ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
685 }
686 }
687
688 static void
ims332_set_curpos(struct xcfb_softc * sc)689 ims332_set_curpos(struct xcfb_softc *sc)
690 {
691 struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
692 uint32_t pos;
693 int s;
694
695 s = spltty();
696 pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
697 ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
698 splx(s);
699 }
700
701 static void
ims332_load_curcmap(struct xcfb_softc * sc)702 ims332_load_curcmap(struct xcfb_softc *sc)
703 {
704 uint8_t *cp = sc->sc_cursor.cc_color;
705 uint32_t rgb;
706
707 /* cursor background */
708 rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
709 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
710
711 /* cursor foreground */
712 rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
713 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
714 }
715
716 static void
ims332_load_curshape(struct xcfb_softc * sc)717 ims332_load_curshape(struct xcfb_softc *sc)
718 {
719 u_int i, img, msk, bits;
720 uint8_t u, *ip, *mp;
721
722 ip = (uint8_t *)sc->sc_cursor.cc_image;
723 mp = (uint8_t *)sc->sc_cursor.cc_mask;
724
725 i = 0;
726 /* 64 pixel scan line is consisted with 8 halfword cursor ram */
727 while (i < sc->sc_cursor.cc_size.y * 8) {
728 /* pad right half 32 pixel when smaller than 33 */
729 if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
730 bits = 0;
731 else {
732 img = *ip++;
733 msk = *mp++;
734 img &= msk; /* cookie off image */
735 u = (msk & 0x0f) << 4 | (img & 0x0f);
736 bits = shuffle[u];
737 u = (msk & 0xf0) | (img & 0xf0) >> 4;
738 bits = (shuffle[u] << 8) | bits;
739 }
740 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
741 i += 1;
742 }
743 /* pad unoccupied scan lines */
744 while (i < CURSOR_MAX_SIZE * 8) {
745 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
746 i += 1;
747 }
748 }
749
750 static void
ims332_write_reg(int regno,uint32_t val)751 ims332_write_reg(int regno, uint32_t val)
752 {
753 void *high8 = (void *)(ioasic_base + IMS332_HIGH);
754 void *low16 = (void *)(ioasic_base + IMS332_WLOW + (regno << 4));
755
756 *(volatile uint16_t *)high8 = (val & 0xff0000) >> 8;
757 *(volatile uint16_t *)low16 = val;
758 }
759
760 #if 0
761 static uint32_t
762 ims332_read_reg(int regno)
763 {
764 void *high8 = (void *)(ioasic_base + IMS332_HIGH);
765 void *low16 = (void *)(ioasic_base + IMS332_RLOW) + (regno << 4);
766 u_int v0, v1;
767
768 v1 = *(volatile uint16_t *)high8;
769 v0 = *(volatile uint16_t *)low16;
770 return (v1 & 0xff00) << 8 | v0;
771 }
772 #endif
773