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