Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dev / tc / xcfb.c
blobfa851e347e7cbee815c70a94c6bc2c9f38110bbf
1 /* $NetBSD: xcfb.c,v 1.50 2009/05/12 14:47:04 cegger Exp $ */
3 /*-
4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
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.
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.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: xcfb.c,v 1.50 2009/05/12 14:47:04 cegger Exp $");
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>
43 #include <sys/bus.h>
44 #include <sys/intr.h>
46 #include <dev/wscons/wsconsio.h>
47 #include <dev/wscons/wsdisplayvar.h>
49 #include <dev/rasops/rasops.h>
50 #include <dev/wsfont/wsfont.h>
52 #include <dev/tc/tcvar.h>
53 #include <dev/tc/ioasicreg.h>
54 #include <dev/ic/ims332reg.h>
55 #include <pmax/pmax/maxine.h>
57 #include <uvm/uvm_extern.h>
59 struct hwcmap256 {
60 #define CMAP_SIZE 256 /* 256 R/G/B entries */
61 uint8_t r[CMAP_SIZE];
62 uint8_t g[CMAP_SIZE];
63 uint8_t b[CMAP_SIZE];
66 struct hwcursor64 {
67 struct wsdisplay_curpos cc_pos;
68 struct wsdisplay_curpos cc_hot;
69 struct wsdisplay_curpos cc_size;
70 struct wsdisplay_curpos cc_magic; /* not used by PMAG-DV */
71 #define CURSOR_MAX_SIZE 64
72 uint8_t cc_color[6];
73 uint64_t cc_image[CURSOR_MAX_SIZE];
74 uint64_t cc_mask[CURSOR_MAX_SIZE];
77 #define XCFB_FB_BASE (XINE_PHYS_CFB_START + 0x2000000)
78 #define XCFB_FB_SIZE 0x100000
80 #define IMS332_HIGH (IOASIC_SLOT_5_START)
81 #define IMS332_RLOW (IOASIC_SLOT_7_START)
82 #define IMS332_WLOW (IOASIC_SLOT_7_START + 0x20000)
84 struct xcfb_softc {
85 vaddr_t sc_vaddr;
86 size_t sc_size;
87 struct rasops_info *sc_ri;
88 struct hwcmap256 sc_cmap; /* software copy of colormap */
89 struct hwcursor64 sc_cursor; /* software copy of cursor */
90 int sc_blanked;
91 /* XXX MAXINE can take PMAG-DV vertical retrace interrupt XXX */
92 int nscreens;
93 /* cursor coordinate is located at upper-left corner */
94 int sc_csr; /* software copy of IMS332 CSR A */
97 static int xcfbmatch(device_t, cfdata_t, void *);
98 static void xcfbattach(device_t, device_t, void *);
100 CFATTACH_DECL_NEW(xcfb, sizeof(struct xcfb_softc),
101 xcfbmatch, xcfbattach, NULL, NULL);
103 static tc_addr_t xcfb_consaddr;
104 static struct rasops_info xcfb_console_ri;
105 static void xcfb_common_init(struct rasops_info *);
106 static void xcfbhwinit(void *);
107 int xcfb_cnattach(void);
109 struct wsscreen_descr xcfb_stdscreen = {
110 "std", 0, 0,
111 0, /* textops */
112 0, 0,
113 WSSCREEN_REVERSE
116 static const struct wsscreen_descr *_xcfb_scrlist[] = {
117 &xcfb_stdscreen,
120 static const struct wsscreen_list xcfb_screenlist = {
121 sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist
124 static int xcfbioctl(void *, void *, u_long, void *, int, struct lwp *);
125 static paddr_t xcfbmmap(void *, void *, off_t, int);
127 static int xcfb_alloc_screen(void *, const struct wsscreen_descr *,
128 void **, int *, int *, long *);
129 static void xcfb_free_screen(void *, void *);
130 static int xcfb_show_screen(void *, void *, int,
131 void (*) (void *, int, int), void *);
133 static const struct wsdisplay_accessops xcfb_accessops = {
134 xcfbioctl,
135 xcfbmmap,
136 xcfb_alloc_screen,
137 xcfb_free_screen,
138 xcfb_show_screen,
139 0 /* load_font */
142 static int xcfbintr(void *);
143 static void xcfb_screenblank(struct xcfb_softc *);
144 static void xcfb_cmap_init(struct xcfb_softc *);
145 static int set_cmap(struct xcfb_softc *, struct wsdisplay_cmap *);
146 static int get_cmap(struct xcfb_softc *, struct wsdisplay_cmap *);
147 static int set_cursor(struct xcfb_softc *, struct wsdisplay_cursor *);
148 static int get_cursor(struct xcfb_softc *, struct wsdisplay_cursor *);
149 static void set_curpos(struct xcfb_softc *, struct wsdisplay_curpos *);
150 static void ims332_loadcmap(struct hwcmap256 *);
151 static void ims332_set_curpos(struct xcfb_softc *);
152 static void ims332_load_curcmap(struct xcfb_softc *);
153 static void ims332_load_curshape(struct xcfb_softc *);
154 static void ims332_write_reg(int, uint32_t);
155 #if 0
156 static uint32_t ims332_read_reg(int);
157 #endif
159 extern long ioasic_base; /* XXX */
162 * Compose 2 bit/pixel cursor image.
163 * M M M M I I I I M I M I M I M I
164 * [ before ] [ after ]
165 * 3 2 1 0 3 2 1 0 3 3 2 2 1 1 0 0
166 * 7 6 5 4 7 6 5 4 7 7 6 6 5 5 4 4
168 static const uint8_t shuffle[256] = {
169 0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15,
170 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55,
171 0x02, 0x03, 0x06, 0x07, 0x12, 0x13, 0x16, 0x17,
172 0x42, 0x43, 0x46, 0x47, 0x52, 0x53, 0x56, 0x57,
173 0x08, 0x09, 0x0c, 0x0d, 0x18, 0x19, 0x1c, 0x1d,
174 0x48, 0x49, 0x4c, 0x4d, 0x58, 0x59, 0x5c, 0x5d,
175 0x0a, 0x0b, 0x0e, 0x0f, 0x1a, 0x1b, 0x1e, 0x1f,
176 0x4a, 0x4b, 0x4e, 0x4f, 0x5a, 0x5b, 0x5e, 0x5f,
177 0x20, 0x21, 0x24, 0x25, 0x30, 0x31, 0x34, 0x35,
178 0x60, 0x61, 0x64, 0x65, 0x70, 0x71, 0x74, 0x75,
179 0x22, 0x23, 0x26, 0x27, 0x32, 0x33, 0x36, 0x37,
180 0x62, 0x63, 0x66, 0x67, 0x72, 0x73, 0x76, 0x77,
181 0x28, 0x29, 0x2c, 0x2d, 0x38, 0x39, 0x3c, 0x3d,
182 0x68, 0x69, 0x6c, 0x6d, 0x78, 0x79, 0x7c, 0x7d,
183 0x2a, 0x2b, 0x2e, 0x2f, 0x3a, 0x3b, 0x3e, 0x3f,
184 0x6a, 0x6b, 0x6e, 0x6f, 0x7a, 0x7b, 0x7e, 0x7f,
185 0x80, 0x81, 0x84, 0x85, 0x90, 0x91, 0x94, 0x95,
186 0xc0, 0xc1, 0xc4, 0xc5, 0xd0, 0xd1, 0xd4, 0xd5,
187 0x82, 0x83, 0x86, 0x87, 0x92, 0x93, 0x96, 0x97,
188 0xc2, 0xc3, 0xc6, 0xc7, 0xd2, 0xd3, 0xd6, 0xd7,
189 0x88, 0x89, 0x8c, 0x8d, 0x98, 0x99, 0x9c, 0x9d,
190 0xc8, 0xc9, 0xcc, 0xcd, 0xd8, 0xd9, 0xdc, 0xdd,
191 0x8a, 0x8b, 0x8e, 0x8f, 0x9a, 0x9b, 0x9e, 0x9f,
192 0xca, 0xcb, 0xce, 0xcf, 0xda, 0xdb, 0xde, 0xdf,
193 0xa0, 0xa1, 0xa4, 0xa5, 0xb0, 0xb1, 0xb4, 0xb5,
194 0xe0, 0xe1, 0xe4, 0xe5, 0xf0, 0xf1, 0xf4, 0xf5,
195 0xa2, 0xa3, 0xa6, 0xa7, 0xb2, 0xb3, 0xb6, 0xb7,
196 0xe2, 0xe3, 0xe6, 0xe7, 0xf2, 0xf3, 0xf6, 0xf7,
197 0xa8, 0xa9, 0xac, 0xad, 0xb8, 0xb9, 0xbc, 0xbd,
198 0xe8, 0xe9, 0xec, 0xed, 0xf8, 0xf9, 0xfc, 0xfd,
199 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf,
200 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff,
203 static int
204 xcfbmatch(device_t parent, cfdata_t match, void *aux)
206 struct tc_attach_args *ta = aux;
208 if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0)
209 return (0);
211 return (1);
214 static void
215 xcfbattach(device_t parent, device_t self, void *aux)
217 struct xcfb_softc *sc = device_private(self);
218 struct tc_attach_args *ta = aux;
219 struct rasops_info *ri;
220 struct wsemuldisplaydev_attach_args waa;
221 int console;
223 console = (ta->ta_addr == xcfb_consaddr);
224 if (console) {
225 sc->sc_ri = ri = &xcfb_console_ri;
226 sc->nscreens = 1;
228 else {
229 ri = malloc(sizeof(struct rasops_info), M_DEVBUF, M_NOWAIT);
230 if (ri == NULL) {
231 printf(": can't alloc memory\n");
232 return;
234 memset(ri, 0, sizeof(struct rasops_info));
236 ri->ri_hw = (void *)ioasic_base;
237 xcfb_common_init(ri);
238 sc->sc_ri = ri;
240 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
242 xcfb_cmap_init(sc);
244 sc->sc_vaddr = ta->ta_addr;
245 sc->sc_blanked = 0;
246 sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
248 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc);
250 waa.console = console;
251 waa.scrdata = &xcfb_screenlist;
252 waa.accessops = &xcfb_accessops;
253 waa.accesscookie = sc;
255 config_found(self, &waa, wsemuldisplaydevprint);
258 static void
259 xcfb_cmap_init(struct xcfb_softc *sc)
261 struct hwcmap256 *cm;
262 const uint8_t *p;
263 int index;
265 cm = &sc->sc_cmap;
266 p = rasops_cmap;
267 for (index = 0; index < CMAP_SIZE; index++, p += 3) {
268 cm->r[index] = p[0];
269 cm->g[index] = p[1];
270 cm->b[index] = p[2];
274 static void
275 xcfb_common_init(struct rasops_info *ri)
277 int cookie;
279 /* initialize colormap and cursor hardware */
280 xcfbhwinit((void *)ri->ri_hw);
282 ri->ri_flg = RI_CENTER;
283 ri->ri_depth = 8;
284 ri->ri_width = 1024;
285 ri->ri_height = 768;
286 ri->ri_stride = 1024;
287 ri->ri_bits = (void *)MIPS_PHYS_TO_KSEG1(XCFB_FB_BASE);
289 /* clear the screen */
290 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
292 wsfont_init();
293 /* prefer 12 pixel wide font */
294 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
295 WSDISPLAY_FONTORDER_L2R);
296 if (cookie <= 0)
297 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
298 WSDISPLAY_FONTORDER_L2R);
299 if (cookie <= 0) {
300 printf("xcfb: font table is empty\n");
301 return;
304 if (wsfont_lock(cookie, &ri->ri_font)) {
305 printf("xcfb: couldn't lock font\n");
306 return;
308 ri->ri_wsfcookie = cookie;
310 rasops_init(ri, 34, 80);
312 /* XXX shouldn't be global */
313 xcfb_stdscreen.nrows = ri->ri_rows;
314 xcfb_stdscreen.ncols = ri->ri_cols;
315 xcfb_stdscreen.textops = &ri->ri_ops;
316 xcfb_stdscreen.capabilities = ri->ri_caps;
320 xcfb_cnattach(void)
322 struct rasops_info *ri;
323 long defattr;
325 ri = &xcfb_console_ri;
326 ri->ri_hw = (void *)ioasic_base;
327 xcfb_common_init(ri);
328 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
329 wsdisplay_cnattach(&xcfb_stdscreen, ri, 0, 0, defattr);
330 xcfb_consaddr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START);
331 return (0);
334 static void
335 xcfbhwinit(void *base)
337 volatile uint32_t *csr;
338 uint32_t i;
339 const uint8_t *p;
341 csr = (volatile uint32_t *)((char *)base + IOASIC_CSR);
342 i = *csr;
343 i &= ~XINE_CSR_VDAC_ENABLE;
344 *csr = i;
345 DELAY(50);
346 i |= XINE_CSR_VDAC_ENABLE;
347 *csr = i;
348 DELAY(50);
349 ims332_write_reg(IMS332_REG_BOOT, 0x2c);
350 ims332_write_reg(IMS332_REG_CSR_A,
351 IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
352 ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
353 ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
354 ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
355 ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
356 ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
357 ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
358 ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
359 ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
360 ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
361 ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
362 ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
363 ims332_write_reg(IMS332_REG_LINE_START, 0x10);
364 ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
365 ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
366 ims332_write_reg(IMS332_REG_CSR_A,
367 IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
369 /* build sane colormap */
370 p = rasops_cmap;
371 for (i = 0; i < CMAP_SIZE; i++, p += 3) {
372 uint32_t bgr;
374 bgr = p[2] << 16 | p[1] << 8 | p[0];
375 ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr);
378 /* clear out cursor image */
379 for (i = 0; i < 512; i++)
380 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
383 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
384 * cursor image. LUT_1 for mask color, while LUT_2 for
385 * image color. LUT_0 will be never used.
387 ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
388 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
389 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
392 static int
393 xcfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
395 struct xcfb_softc *sc = v;
396 struct rasops_info *ri = sc->sc_ri;
397 int turnoff, error;
399 switch (cmd) {
400 case WSDISPLAYIO_GTYPE:
401 *(u_int *)data = WSDISPLAY_TYPE_XCFB;
402 return (0);
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);
413 case WSDISPLAYIO_GETCMAP:
414 return get_cmap(sc, (struct wsdisplay_cmap *)data);
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);
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);
428 return (0);
430 case WSDISPLAYIO_GVIDEO:
431 *(u_int *)data = sc->sc_blanked ?
432 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
433 return (0);
435 case WSDISPLAYIO_GCURPOS:
436 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
437 return (0);
439 case WSDISPLAYIO_SCURPOS:
440 set_curpos(sc, (struct wsdisplay_curpos *)data);
441 ims332_set_curpos(sc);
442 return (0);
444 case WSDISPLAYIO_GCURMAX:
445 ((struct wsdisplay_curpos *)data)->x =
446 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
447 return (0);
449 case WSDISPLAYIO_GCURSOR:
450 return get_cursor(sc, (struct wsdisplay_cursor *)data);
452 case WSDISPLAYIO_SCURSOR:
453 return set_cursor(sc, (struct wsdisplay_cursor *)data);
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);
464 return (0);
466 return (EPASSTHROUGH);
469 static paddr_t
470 xcfbmmap(void *v, void *vs, off_t offset, int prot)
473 if (offset >= XCFB_FB_SIZE || offset < 0)
474 return (-1);
475 return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset));
478 static int
479 xcfb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
480 int *curxp, int *curyp, long *attrp)
482 struct xcfb_softc *sc = v;
483 struct rasops_info *ri = sc->sc_ri;
484 long defattr;
486 if (sc->nscreens > 0)
487 return (ENOMEM);
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);
498 static void
499 xcfb_free_screen(void *v, void *cookie)
501 struct xcfb_softc *sc = v;
503 if (sc->sc_ri == &xcfb_console_ri)
504 panic("xcfb_free_screen: console");
506 sc->nscreens--;
509 static int
510 xcfb_show_screen(void *v, void *cookie, int waitok,
511 void (*cb)(void *, int, int), void *cbarg)
514 return (0);
517 static int
518 xcfbintr(void *v)
520 struct xcfb_softc *sc = v;
521 uint32_t *intr, i;
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);
530 static void
531 xcfb_screenblank(struct xcfb_softc *sc)
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);
540 static int
541 get_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p)
543 u_int index = p->index, count = p->count;
544 int error;
546 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
547 return (EINVAL);
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;
559 static int
560 set_cmap(struct xcfb_softc *sc, struct wsdisplay_cmap *p)
562 struct hwcmap256 cmap;
563 u_int index = p->index, count = p->count;
564 int error;
566 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
567 return (EINVAL);
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);
584 static int
585 set_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p)
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;
592 v = p->which;
593 if (v & WSDISPLAY_CURSOR_DOCMAP) {
594 index = p->cmap.index;
595 count = p->cmap.count;
597 if (index >= 2 || index + count > 2)
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;
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;
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);
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);
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);
643 if (v & WSDISPLAY_CURSOR_DOPOS) {
644 set_curpos(sc, &p->pos);
645 ims332_set_curpos(sc);
648 return (0);
649 #undef cc
652 static int
653 get_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p)
655 return (EPASSTHROUGH); /* XXX */
658 static void
659 set_curpos(struct xcfb_softc *sc, struct wsdisplay_curpos *curpos)
661 struct rasops_info *ri = sc->sc_ri;
662 int x = curpos->x, y = curpos->y;
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;
676 static void
677 ims332_loadcmap(struct hwcmap256 *cm)
679 int i;
680 uint32_t rgb;
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);
688 static void
689 ims332_set_curpos(struct xcfb_softc *sc)
691 struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
692 uint32_t pos;
693 int s;
695 s = spltty();
696 pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
697 ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
698 splx(s);
701 static void
702 ims332_load_curcmap(struct xcfb_softc *sc)
704 uint8_t *cp = sc->sc_cursor.cc_color;
705 uint32_t rgb;
707 /* cursor background */
708 rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
709 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
711 /* cursor foreground */
712 rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
713 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
716 static void
717 ims332_load_curshape(struct xcfb_softc *sc)
719 u_int i, img, msk, bits;
720 uint8_t u, *ip, *mp;
722 ip = (uint8_t *)sc->sc_cursor.cc_image;
723 mp = (uint8_t *)sc->sc_cursor.cc_mask;
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;
740 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
741 i += 1;
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;
750 static void
751 ims332_write_reg(int regno, uint32_t val)
753 void *high8 = (void *)(ioasic_base + IMS332_HIGH);
754 void *low16 = (void *)(ioasic_base + IMS332_WLOW + (regno << 4));
756 *(volatile uint16_t *)high8 = (val & 0xff0000) >> 8;
757 *(volatile uint16_t *)low16 = val;
760 #if 0
761 static uint32_t
762 ims332_read_reg(int regno)
764 void *high8 = (void *)(ioasic_base + IMS332_HIGH);
765 void *low16 = (void *)(ioasic_base + IMS332_RLOW) + (regno << 4);
766 u_int v0, v1;
768 v1 = *(volatile uint16_t *)high8;
769 v0 = *(volatile uint16_t *)low16;
770 return (v1 & 0xff00) << 8 | v0;
772 #endif