xcfb.c revision 1.57 1 /* $NetBSD: xcfb.c,v 1.57 2019/11/10 21:16:37 chs 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.57 2019/11/10 21:16:37 chs 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
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
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);
249 }
250
251 static void
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
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
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
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
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_GINFO:
400 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
401 wsd_fbip->height = ri->ri_height;
402 wsd_fbip->width = ri->ri_width;
403 wsd_fbip->depth = ri->ri_depth;
404 wsd_fbip->cmsize = CMAP_SIZE;
405 #undef fbt
406 return (0);
407
408 case WSDISPLAYIO_GETCMAP:
409 return get_cmap(sc, (struct wsdisplay_cmap *)data);
410
411 case WSDISPLAYIO_PUTCMAP:
412 error = set_cmap(sc, (struct wsdisplay_cmap *)data);
413 if (error == 0)
414 ims332_loadcmap(&sc->sc_cmap);
415 return (error);
416
417 case WSDISPLAYIO_SVIDEO:
418 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
419 if (sc->sc_blanked != turnoff) {
420 sc->sc_blanked = turnoff;
421 xcfb_screenblank(sc);
422 }
423 return (0);
424
425 case WSDISPLAYIO_GVIDEO:
426 *(u_int *)data = sc->sc_blanked ?
427 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
428 return (0);
429
430 case WSDISPLAYIO_GCURPOS:
431 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
432 return (0);
433
434 case WSDISPLAYIO_SCURPOS:
435 set_curpos(sc, (struct wsdisplay_curpos *)data);
436 ims332_set_curpos(sc);
437 return (0);
438
439 case WSDISPLAYIO_GCURMAX:
440 ((struct wsdisplay_curpos *)data)->x =
441 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
442 return (0);
443
444 case WSDISPLAYIO_GCURSOR:
445 return get_cursor(sc, (struct wsdisplay_cursor *)data);
446
447 case WSDISPLAYIO_SCURSOR:
448 return set_cursor(sc, (struct wsdisplay_cursor *)data);
449
450 case WSDISPLAYIO_SMODE:
451 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
452 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
453 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
454 xcfb_cmap_init(sc);
455 ims332_loadcmap(&sc->sc_cmap);
456 sc->sc_blanked = 0;
457 xcfb_screenblank(sc);
458 }
459 return (0);
460 }
461 return (EPASSTHROUGH);
462 }
463
464 static paddr_t
465 xcfbmmap(void *v, void *vs, off_t offset, int prot)
466 {
467
468 if (offset >= XCFB_FB_SIZE || offset < 0)
469 return (-1);
470 return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset));
471 }
472
473 static int
474 xcfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
475 int *curxp, int *curyp, long *attrp)
476 {
477 struct xcfb_softc *sc = v;
478 struct rasops_info *ri = sc->sc_ri;
479 long defattr;
480
481 if (sc->nscreens > 0)
482 return (ENOMEM);
483
484 *cookiep = ri; /* one and only for now */
485 *curxp = 0;
486 *curyp = 0;
487 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
488 *attrp = defattr;
489 sc->nscreens++;
490 return (0);
491 }
492
493 static void
494 xcfb_free_screen(void *v, void *cookie)
495 {
496 struct xcfb_softc *sc = v;
497
498 if (sc->sc_ri == &xcfb_console_ri)
499 panic("xcfb_free_screen: console");
500
501 sc->nscreens--;
502 }
503
504 static int
505 xcfb_show_screen(void *v, void *cookie, int waitok,
506 void (*cb)(void *, int, int), void *cbarg)
507 {
508
509 return (0);
510 }
511
512 static int
513 xcfbintr(void *v)
514 {
515 struct xcfb_softc *sc = v;
516 uint32_t *intr, i;
517
518 intr = (uint32_t *)((char *)sc->sc_ri->ri_hw + IOASIC_INTR);
519 i = *intr;
520 i &= ~XINE_INTR_VINT;
521 *intr = i;
522 return (1);
523 }
524
525 static void
526 xcfb_screenblank(struct xcfb_softc *sc)
527 {
528 if (sc->sc_blanked)
529 sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK;
530 else
531 sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK;
532 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
533 }
534
535 static int
536 get_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p)
537 {
538 u_int index = p->index, count = p->count;
539 int error;
540
541 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
542 return (EINVAL);
543
544 error = copyout(&sc->sc_cmap.r[index], p->red, count);
545 if (error)
546 return error;
547 error = copyout(&sc->sc_cmap.g[index], p->green, count);
548 if (error)
549 return error;
550 error = copyout(&sc->sc_cmap.b[index], p->blue, count);
551 return error;
552 }
553
554 static int
555 set_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p)
556 {
557 struct hwcmap256 cmap;
558 u_int index = p->index, count = p->count;
559 int error;
560
561 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
562 return (EINVAL);
563
564 error = copyin(p->red, &cmap.r[index], count);
565 if (error)
566 return error;
567 error = copyin(p->green, &cmap.g[index], count);
568 if (error)
569 return error;
570 error = copyin(p->blue, &cmap.b[index], count);
571 if (error)
572 return error;
573 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
574 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
575 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
576 return (0);
577 }
578
579 static int
580 set_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p)
581 {
582 #define cc (&sc->sc_cursor)
583 u_int v, index = 0, count = 0, icount = 0;
584 uint8_t r[2], g[2], b[2], image[512], mask[512];
585 int error;
586
587 v = p->which;
588 if (v & WSDISPLAY_CURSOR_DOCMAP) {
589 index = p->cmap.index;
590 count = p->cmap.count;
591
592 if (index >= 2 || count > 2 - index)
593 return (EINVAL);
594 error = copyin(p->cmap.red, &r[index], count);
595 if (error)
596 return error;
597 error = copyin(p->cmap.green, &g[index], count);
598 if (error)
599 return error;
600 error = copyin(p->cmap.blue, &b[index], count);
601 if (error)
602 return error;
603 }
604 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
605 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
606 return (EINVAL);
607 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
608 error = copyin(p->image, image, icount);
609 if (error)
610 return error;
611 error = copyin(p->mask, mask, icount);
612 if (error)
613 return error;
614 }
615
616 if (v & WSDISPLAY_CURSOR_DOCMAP) {
617 memcpy(&cc->cc_color[index], &r[index], count);
618 memcpy(&cc->cc_color[index + 2], &g[index], count);
619 memcpy(&cc->cc_color[index + 4], &b[index], count);
620 ims332_load_curcmap(sc);
621 }
622 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
623 cc->cc_size = p->size;
624 memset(cc->cc_image, 0, sizeof cc->cc_image);
625 memcpy(cc->cc_image, image, icount);
626 memset(cc->cc_mask, 0, sizeof cc->cc_mask);
627 memcpy(cc->cc_mask, mask, icount);
628 ims332_load_curshape(sc);
629 }
630 if (v & WSDISPLAY_CURSOR_DOCUR) {
631 cc->cc_hot = p->hot;
632 if (p->enable)
633 sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
634 else
635 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
636 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
637 }
638 if (v & WSDISPLAY_CURSOR_DOPOS) {
639 set_curpos(sc, &p->pos);
640 ims332_set_curpos(sc);
641 }
642
643 return (0);
644 #undef cc
645 }
646
647 static int
648 get_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p)
649 {
650 return (EPASSTHROUGH); /* XXX */
651 }
652
653 static void
654 set_curpos(struct xcfb_softc *sc, struct wsdisplay_curpos *curpos)
655 {
656 struct rasops_info *ri = sc->sc_ri;
657 int x = curpos->x, y = curpos->y;
658
659 if (y < 0)
660 y = 0;
661 else if (y > ri->ri_height)
662 y = ri->ri_height;
663 if (x < 0)
664 x = 0;
665 else if (x > ri->ri_width)
666 x = ri->ri_width;
667 sc->sc_cursor.cc_pos.x = x;
668 sc->sc_cursor.cc_pos.y = y;
669 }
670
671 static void
672 ims332_loadcmap(struct hwcmap256 *cm)
673 {
674 int i;
675 uint32_t rgb;
676
677 for (i = 0; i < CMAP_SIZE; i++) {
678 rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
679 ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
680 }
681 }
682
683 static void
684 ims332_set_curpos(struct xcfb_softc *sc)
685 {
686 struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
687 uint32_t pos;
688 int s;
689
690 s = spltty();
691 pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
692 ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
693 splx(s);
694 }
695
696 static void
697 ims332_load_curcmap(struct xcfb_softc *sc)
698 {
699 uint8_t *cp = sc->sc_cursor.cc_color;
700 uint32_t rgb;
701
702 /* cursor background */
703 rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
704 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
705
706 /* cursor foreground */
707 rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
708 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
709 }
710
711 static void
712 ims332_load_curshape(struct xcfb_softc *sc)
713 {
714 u_int i, img, msk, bits;
715 uint8_t u, *ip, *mp;
716
717 ip = (uint8_t *)sc->sc_cursor.cc_image;
718 mp = (uint8_t *)sc->sc_cursor.cc_mask;
719
720 i = 0;
721 /* 64 pixel scan line is consisted with 8 halfword cursor ram */
722 while (i < sc->sc_cursor.cc_size.y * 8) {
723 /* pad right half 32 pixel when smaller than 33 */
724 if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
725 bits = 0;
726 else {
727 img = *ip++;
728 msk = *mp++;
729 img &= msk; /* cookie off image */
730 u = (msk & 0x0f) << 4 | (img & 0x0f);
731 bits = shuffle[u];
732 u = (msk & 0xf0) | (img & 0xf0) >> 4;
733 bits = (shuffle[u] << 8) | bits;
734 }
735 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
736 i += 1;
737 }
738 /* pad unoccupied scan lines */
739 while (i < CURSOR_MAX_SIZE * 8) {
740 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
741 i += 1;
742 }
743 }
744
745 static void
746 ims332_write_reg(int regno, uint32_t val)
747 {
748 void *high8 = (void *)(ioasic_base + IMS332_HIGH);
749 void *low16 = (void *)(ioasic_base + IMS332_WLOW + (regno << 4));
750
751 *(volatile uint16_t *)high8 = (val & 0xff0000) >> 8;
752 *(volatile uint16_t *)low16 = val;
753 }
754
755 #if 0
756 static uint32_t
757 ims332_read_reg(int regno)
758 {
759 void *high8 = (void *)(ioasic_base + IMS332_HIGH);
760 void *low16 = (void *)(ioasic_base + IMS332_RLOW) + (regno << 4);
761 u_int v0, v1;
762
763 v1 = *(volatile uint16_t *)high8;
764 v0 = *(volatile uint16_t *)low16;
765 return (v1 & 0xff00) << 8 | v0;
766 }
767 #endif
768