xcfb.c revision 1.45.20.1 1 /* $NetBSD: xcfb.c,v 1.45.20.1 2009/05/04 08:13:20 yamt 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.45.20.1 2009/05/04 08:13:20 yamt 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 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 */
95 };
96
97 static int xcfbmatch(struct device *, struct cfdata *, void *);
98 static void xcfbattach(struct device *, struct device *, void *);
99
100 CFATTACH_DECL_NEW(xcfb, sizeof(struct xcfb_softc),
101 xcfbmatch, xcfbattach, NULL, NULL);
102
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);
108
109 struct wsscreen_descr xcfb_stdscreen = {
110 "std", 0, 0,
111 0, /* textops */
112 0, 0,
113 WSSCREEN_REVERSE
114 };
115
116 static const struct wsscreen_descr *_xcfb_scrlist[] = {
117 &xcfb_stdscreen,
118 };
119
120 static const struct wsscreen_list xcfb_screenlist = {
121 sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist
122 };
123
124 static int xcfbioctl(void *, void *, u_long, void *, int, struct lwp *);
125 static paddr_t xcfbmmap(void *, void *, off_t, int);
126
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 *);
132
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 */
140 };
141
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, u_int32_t);
155 #if 0
156 static u_int32_t ims332_read_reg(int);
157 #endif
158
159 extern long ioasic_base; /* XXX */
160
161 /*
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
167 */
168 static const u_int8_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,
201 };
202
203 static int
204 xcfbmatch(device_t parent, cfdata_t match, void *aux)
205 {
206 struct tc_attach_args *ta = aux;
207
208 if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0)
209 return (0);
210
211 return (1);
212 }
213
214 static void
215 xcfbattach(device_t parent, device_t self, void *aux)
216 {
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;
222
223 console = (ta->ta_addr == xcfb_consaddr);
224 if (console) {
225 sc->sc_ri = ri = &xcfb_console_ri;
226 sc->nscreens = 1;
227 }
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;
233 }
234 memset(ri, 0, sizeof(struct rasops_info));
235
236 ri->ri_hw = (void *)ioasic_base;
237 xcfb_common_init(ri);
238 sc->sc_ri = ri;
239 }
240 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
241
242 xcfb_cmap_init(sc);
243
244 sc->sc_vaddr = ta->ta_addr;
245 sc->sc_blanked = 0;
246 sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
247
248 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc);
249
250 waa.console = console;
251 waa.scrdata = &xcfb_screenlist;
252 waa.accessops = &xcfb_accessops;
253 waa.accesscookie = sc;
254
255 config_found(self, &waa, wsemuldisplaydevprint);
256 }
257
258 static void
259 xcfb_cmap_init(struct xcfb_softc *sc)
260 {
261 struct hwcmap256 *cm;
262 const u_int8_t *p;
263 int index;
264
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];
271 }
272 }
273
274 static void
275 xcfb_common_init(struct rasops_info *ri)
276 {
277 int cookie;
278
279 /* initialize colormap and cursor hardware */
280 xcfbhwinit((void *)ri->ri_hw);
281
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);
288
289 /* clear the screen */
290 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
291
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;
302 }
303
304 if (wsfont_lock(cookie, &ri->ri_font)) {
305 printf("xcfb: couldn't lock font\n");
306 return;
307 }
308 ri->ri_wsfcookie = cookie;
309
310 rasops_init(ri, 34, 80);
311
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;
317 }
318
319 int
320 xcfb_cnattach(void)
321 {
322 struct rasops_info *ri;
323 long defattr;
324
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);
332 }
333
334 static void
335 xcfbhwinit(void *base)
336 {
337 volatile u_int32_t *csr;
338 u_int32_t i;
339 const u_int8_t *p;
340
341 csr = (volatile u_int32_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);
368
369 /* build sane colormap */
370 p = rasops_cmap;
371 for (i = 0; i < CMAP_SIZE; i++, p += 3) {
372 u_int32_t bgr;
373
374 bgr = p[2] << 16 | p[1] << 8 | p[0];
375 ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr);
376 }
377
378 /* clear out cursor image */
379 for (i = 0; i < 512; i++)
380 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
381
382 /*
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.
386 */
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);
390 }
391
392 static int
393 xcfbioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l)
394 {
395 struct xcfb_softc *sc = v;
396 struct rasops_info *ri = sc->sc_ri;
397 int turnoff, error;
398
399 switch (cmd) {
400 case WSDISPLAYIO_GTYPE:
401 *(u_int *)data = WSDISPLAY_TYPE_XCFB;
402 return (0);
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
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
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
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
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
518 xcfbintr(void *v)
519 {
520 struct xcfb_softc *sc = v;
521 u_int32_t *intr, i;
522
523 intr = (u_int32_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
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
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
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
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 || 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;
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
653 get_cursor(struct xcfb_softc *sc, struct wsdisplay_cursor *p)
654 {
655 return (EPASSTHROUGH); /* XXX */
656 }
657
658 static void
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
677 ims332_loadcmap(struct hwcmap256 *cm)
678 {
679 int i;
680 u_int32_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
689 ims332_set_curpos(struct xcfb_softc *sc)
690 {
691 struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
692 u_int32_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
702 ims332_load_curcmap(struct xcfb_softc *sc)
703 {
704 u_int8_t *cp = sc->sc_cursor.cc_color;
705 u_int32_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
717 ims332_load_curshape(struct xcfb_softc *sc)
718 {
719 u_int i, img, msk, bits;
720 u_int8_t u, *ip, *mp;
721
722 ip = (u_int8_t *)sc->sc_cursor.cc_image;
723 mp = (u_int8_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
751 ims332_write_reg(int regno, u_int32_t val)
752 {
753 void *high8 = (void *)(ioasic_base + IMS332_HIGH);
754 void *low16 = (void *)(ioasic_base + IMS332_WLOW + (regno << 4));
755
756 *(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8;
757 *(volatile u_int16_t *)low16 = val;
758 }
759
760 #if 0
761 static u_int32_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 u_int16_t *)high8;
769 v0 = *(volatile u_int16_t *)low16;
770 return (v1 & 0xff00) << 8 | v0;
771 }
772 #endif
773