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