xcfb.c revision 1.37 1 /* $NetBSD: xcfb.c,v 1.37 2005/01/02 20:41:20 mhitch 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.37 2005/01/02 20:41:20 mhitch 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 proc *);
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(parent, match, aux)
207 struct device *parent;
208 struct cfdata *match;
209 void *aux;
210 {
211 struct tc_attach_args *ta = aux;
212
213 if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0)
214 return (0);
215
216 return (1);
217 }
218
219 static void
220 xcfbattach(parent, self, aux)
221 struct device *parent, *self;
222 void *aux;
223 {
224 struct xcfb_softc *sc = (struct xcfb_softc *)self;
225 struct tc_attach_args *ta = aux;
226 struct rasops_info *ri;
227 struct wsemuldisplaydev_attach_args waa;
228 int console;
229
230 console = (ta->ta_addr == xcfb_consaddr);
231 if (console) {
232 sc->sc_ri = ri = &xcfb_console_ri;
233 sc->nscreens = 1;
234 }
235 else {
236 MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
237 M_DEVBUF, M_NOWAIT);
238 if (ri == NULL) {
239 printf(": can't alloc memory\n");
240 return;
241 }
242 memset(ri, 0, sizeof(struct rasops_info));
243
244 ri->ri_hw = (void *)ioasic_base;
245 xcfb_common_init(ri);
246 sc->sc_ri = ri;
247 }
248 printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
249
250 xcfb_cmap_init(sc);
251
252 sc->sc_vaddr = ta->ta_addr;
253 sc->sc_blanked = 0;
254 sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
255
256 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc);
257
258 waa.console = console;
259 waa.scrdata = &xcfb_screenlist;
260 waa.accessops = &xcfb_accessops;
261 waa.accesscookie = sc;
262
263 config_found(self, &waa, wsemuldisplaydevprint);
264 }
265
266 static void
267 xcfb_cmap_init(sc)
268 struct xcfb_softc *sc;
269 {
270 struct hwcmap256 *cm;
271 const u_int8_t *p;
272 int index;
273
274 cm = &sc->sc_cmap;
275 p = rasops_cmap;
276 for (index = 0; index < CMAP_SIZE; index++, p += 3) {
277 cm->r[index] = p[0];
278 cm->g[index] = p[1];
279 cm->b[index] = p[2];
280 }
281 }
282
283 static void
284 xcfb_common_init(ri)
285 struct rasops_info *ri;
286 {
287 int cookie;
288
289 /* initialize colormap and cursor hardware */
290 xcfbhwinit((caddr_t)ri->ri_hw);
291
292 ri->ri_flg = RI_CENTER;
293 ri->ri_depth = 8;
294 ri->ri_width = 1024;
295 ri->ri_height = 768;
296 ri->ri_stride = 1024;
297 ri->ri_bits = (caddr_t)MIPS_PHYS_TO_KSEG1(XCFB_FB_BASE);
298
299 /* clear the screen */
300 memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
301
302 wsfont_init();
303 /* prefer 12 pixel wide font */
304 cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
305 WSDISPLAY_FONTORDER_L2R);
306 if (cookie <= 0)
307 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
308 WSDISPLAY_FONTORDER_L2R);
309 if (cookie <= 0) {
310 printf("xcfb: font table is empty\n");
311 return;
312 }
313
314 if (wsfont_lock(cookie, &ri->ri_font)) {
315 printf("xcfb: couldn't lock font\n");
316 return;
317 }
318 ri->ri_wsfcookie = cookie;
319
320 rasops_init(ri, 34, 80);
321
322 /* XXX shouldn't be global */
323 xcfb_stdscreen.nrows = ri->ri_rows;
324 xcfb_stdscreen.ncols = ri->ri_cols;
325 xcfb_stdscreen.textops = &ri->ri_ops;
326 xcfb_stdscreen.capabilities = ri->ri_caps;
327 }
328
329 int
330 xcfb_cnattach()
331 {
332 struct rasops_info *ri;
333 long defattr;
334
335 ri = &xcfb_console_ri;
336 ri->ri_hw = (void *)ioasic_base;
337 xcfb_common_init(ri);
338 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
339 wsdisplay_cnattach(&xcfb_stdscreen, ri, 0, 0, defattr);
340 xcfb_consaddr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START);
341 return (0);
342 }
343
344 static void
345 xcfbhwinit(base)
346 caddr_t base;
347 {
348 volatile u_int32_t *csr;
349 u_int32_t i;
350 const u_int8_t *p;
351
352 csr = (volatile u_int32_t *)(base + IOASIC_CSR);
353 i = *csr;
354 i &= ~XINE_CSR_VDAC_ENABLE;
355 *csr = i;
356 DELAY(50);
357 i |= XINE_CSR_VDAC_ENABLE;
358 *csr = i;
359 DELAY(50);
360 ims332_write_reg(IMS332_REG_BOOT, 0x2c);
361 ims332_write_reg(IMS332_REG_CSR_A,
362 IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
363 ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
364 ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
365 ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
366 ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
367 ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
368 ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
369 ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
370 ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
371 ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
372 ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
373 ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
374 ims332_write_reg(IMS332_REG_LINE_START, 0x10);
375 ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
376 ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
377 ims332_write_reg(IMS332_REG_CSR_A,
378 IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
379
380 /* build sane colormap */
381 p = rasops_cmap;
382 for (i = 0; i < CMAP_SIZE; i++, p += 3) {
383 u_int32_t bgr;
384
385 bgr = p[2] << 16 | p[1] << 8 | p[0];
386 ims332_write_reg(IMS332_REG_LUT_BASE + i, bgr);
387 }
388
389 /* clear out cursor image */
390 for (i = 0; i < 512; i++)
391 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
392
393 /*
394 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
395 * cursor image. LUT_1 for mask color, while LUT_2 for
396 * image color. LUT_0 will be never used.
397 */
398 ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
399 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
400 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
401 }
402
403 static int
404 xcfbioctl(v, cmd, data, flag, p)
405 void *v;
406 u_long cmd;
407 caddr_t data;
408 int flag;
409 struct proc *p;
410 {
411 struct xcfb_softc *sc = v;
412 struct rasops_info *ri = sc->sc_ri;
413 int turnoff, error;
414
415 switch (cmd) {
416 case WSDISPLAYIO_GTYPE:
417 *(u_int *)data = WSDISPLAY_TYPE_XCFB;
418 return (0);
419
420 case WSDISPLAYIO_GINFO:
421 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
422 wsd_fbip->height = ri->ri_height;
423 wsd_fbip->width = ri->ri_width;
424 wsd_fbip->depth = ri->ri_depth;
425 wsd_fbip->cmsize = CMAP_SIZE;
426 #undef fbt
427 return (0);
428
429 case WSDISPLAYIO_GETCMAP:
430 return get_cmap(sc, (struct wsdisplay_cmap *)data);
431
432 case WSDISPLAYIO_PUTCMAP:
433 error = set_cmap(sc, (struct wsdisplay_cmap *)data);
434 if (error == 0)
435 ims332_loadcmap(&sc->sc_cmap);
436 return (error);
437
438 case WSDISPLAYIO_SVIDEO:
439 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
440 if (sc->sc_blanked != turnoff) {
441 sc->sc_blanked = turnoff;
442 xcfb_screenblank(sc);
443 }
444 return (0);
445
446 case WSDISPLAYIO_GVIDEO:
447 *(u_int *)data = sc->sc_blanked ?
448 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
449 return (0);
450
451 case WSDISPLAYIO_GCURPOS:
452 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
453 return (0);
454
455 case WSDISPLAYIO_SCURPOS:
456 set_curpos(sc, (struct wsdisplay_curpos *)data);
457 ims332_set_curpos(sc);
458 return (0);
459
460 case WSDISPLAYIO_GCURMAX:
461 ((struct wsdisplay_curpos *)data)->x =
462 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
463 return (0);
464
465 case WSDISPLAYIO_GCURSOR:
466 return get_cursor(sc, (struct wsdisplay_cursor *)data);
467
468 case WSDISPLAYIO_SCURSOR:
469 return set_cursor(sc, (struct wsdisplay_cursor *)data);
470
471 case WSDISPLAYIO_SMODE:
472 if (*(int *)data == WSDISPLAYIO_MODE_EMUL) {
473 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
474 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
475 xcfb_cmap_init(sc);
476 ims332_loadcmap(&sc->sc_cmap);
477 sc->sc_blanked = 0;
478 xcfb_screenblank(sc);
479 }
480 return (0);
481 }
482 return (EPASSTHROUGH);
483 }
484
485 static paddr_t
486 xcfbmmap(v, offset, prot)
487 void *v;
488 off_t offset;
489 int prot;
490 {
491
492 if (offset >= XCFB_FB_SIZE || offset < 0)
493 return (-1);
494 return mips_btop(MIPS_KSEG1_TO_PHYS(XCFB_FB_BASE + offset));
495 }
496
497 static int
498 xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
499 void *v;
500 const struct wsscreen_descr *type;
501 void **cookiep;
502 int *curxp, *curyp;
503 long *attrp;
504 {
505 struct xcfb_softc *sc = v;
506 struct rasops_info *ri = sc->sc_ri;
507 long defattr;
508
509 if (sc->nscreens > 0)
510 return (ENOMEM);
511
512 *cookiep = ri; /* one and only for now */
513 *curxp = 0;
514 *curyp = 0;
515 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
516 *attrp = defattr;
517 sc->nscreens++;
518 return (0);
519 }
520
521 static void
522 xcfb_free_screen(v, cookie)
523 void *v;
524 void *cookie;
525 {
526 struct xcfb_softc *sc = v;
527
528 if (sc->sc_ri == &xcfb_console_ri)
529 panic("xcfb_free_screen: console");
530
531 sc->nscreens--;
532 }
533
534 static int
535 xcfb_show_screen(v, cookie, waitok, cb, cbarg)
536 void *v;
537 void *cookie;
538 int waitok;
539 void (*cb)(void *, int, int);
540 void *cbarg;
541 {
542
543 return (0);
544 }
545
546 static int
547 xcfbintr(v)
548 void *v;
549 {
550 struct xcfb_softc *sc = v;
551 u_int32_t *intr, i;
552
553 intr = (u_int32_t *)((caddr_t)sc->sc_ri->ri_hw + IOASIC_INTR);
554 i = *intr;
555 i &= ~XINE_INTR_VINT;
556 *intr = i;
557 return (1);
558 }
559
560 static void
561 xcfb_screenblank(sc)
562 struct xcfb_softc *sc;
563 {
564 if (sc->sc_blanked)
565 sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK;
566 else
567 sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK;
568 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
569 }
570
571 static int
572 get_cmap(sc, p)
573 struct xcfb_softc *sc;
574 struct wsdisplay_cmap *p;
575 {
576 u_int index = p->index, count = p->count;
577 int error;
578
579 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
580 return (EINVAL);
581
582 error = copyout(&sc->sc_cmap.r[index], p->red, count);
583 if (error)
584 return error;
585 error = copyout(&sc->sc_cmap.g[index], p->green, count);
586 if (error)
587 return error;
588 error = copyout(&sc->sc_cmap.b[index], p->blue, count);
589 return error;
590 }
591
592 static int
593 set_cmap(sc, p)
594 struct xcfb_softc *sc;
595 struct wsdisplay_cmap *p;
596 {
597 struct hwcmap256 cmap;
598 u_int index = p->index, count = p->count;
599 int error;
600
601 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
602 return (EINVAL);
603
604 error = copyin(p->red, &cmap.r[index], count);
605 if (error)
606 return error;
607 error = copyin(p->green, &cmap.g[index], count);
608 if (error)
609 return error;
610 error = copyin(p->blue, &cmap.b[index], count);
611 if (error)
612 return error;
613 memcpy(&sc->sc_cmap.r[index], &cmap.r[index], count);
614 memcpy(&sc->sc_cmap.g[index], &cmap.g[index], count);
615 memcpy(&sc->sc_cmap.b[index], &cmap.b[index], count);
616 return (0);
617 }
618
619 static int
620 set_cursor(sc, p)
621 struct xcfb_softc *sc;
622 struct wsdisplay_cursor *p;
623 {
624 #define cc (&sc->sc_cursor)
625 u_int v, index = 0, count = 0, icount = 0;
626 uint8_t r[2], g[2], b[2], image[512], mask[512];
627 int error;
628
629 v = p->which;
630 if (v & WSDISPLAY_CURSOR_DOCMAP) {
631 index = p->cmap.index;
632 count = p->cmap.count;
633
634 if (index >= 2 || index + count > 2)
635 return (EINVAL);
636 error = copyin(p->cmap.red, &r[index], count);
637 if (error)
638 return error;
639 error = copyin(p->cmap.green, &g[index], count);
640 if (error)
641 return error;
642 error = copyin(p->cmap.blue, &b[index], count);
643 if (error)
644 return error;
645 }
646 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
647 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
648 return (EINVAL);
649 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
650 error = copyin(p->image, image, icount);
651 if (error)
652 return error;
653 error = copyin(p->mask, mask, icount);
654 if (error)
655 return error;
656 }
657
658 if (v & WSDISPLAY_CURSOR_DOCMAP) {
659 memcpy(&cc->cc_color[index], &r[index], count);
660 memcpy(&cc->cc_color[index + 2], &g[index], count);
661 memcpy(&cc->cc_color[index + 4], &b[index], count);
662 ims332_load_curcmap(sc);
663 }
664 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
665 cc->cc_size = p->size;
666 memset(cc->cc_image, 0, sizeof cc->cc_image);
667 memcpy(cc->cc_image, image, icount);
668 memset(cc->cc_mask, 0, sizeof cc->cc_mask);
669 memcpy(cc->cc_mask, mask, icount);
670 ims332_load_curshape(sc);
671 }
672 if (v & WSDISPLAY_CURSOR_DOCUR) {
673 cc->cc_hot = p->hot;
674 if (p->enable)
675 sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
676 else
677 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
678 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
679 }
680 if (v & WSDISPLAY_CURSOR_DOPOS) {
681 set_curpos(sc, &p->pos);
682 ims332_set_curpos(sc);
683 }
684
685 return (0);
686 #undef cc
687 }
688
689 static int
690 get_cursor(sc, p)
691 struct xcfb_softc *sc;
692 struct wsdisplay_cursor *p;
693 {
694 return (EPASSTHROUGH); /* XXX */
695 }
696
697 static void
698 set_curpos(sc, curpos)
699 struct xcfb_softc *sc;
700 struct wsdisplay_curpos *curpos;
701 {
702 struct rasops_info *ri = sc->sc_ri;
703 int x = curpos->x, y = curpos->y;
704
705 if (y < 0)
706 y = 0;
707 else if (y > ri->ri_height)
708 y = ri->ri_height;
709 if (x < 0)
710 x = 0;
711 else if (x > ri->ri_width)
712 x = ri->ri_width;
713 sc->sc_cursor.cc_pos.x = x;
714 sc->sc_cursor.cc_pos.y = y;
715 }
716
717 static void
718 ims332_loadcmap(cm)
719 struct hwcmap256 *cm;
720 {
721 int i;
722 u_int32_t rgb;
723
724 for (i = 0; i < CMAP_SIZE; i++) {
725 rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
726 ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
727 }
728 }
729
730 static void
731 ims332_set_curpos(sc)
732 struct xcfb_softc *sc;
733 {
734 struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
735 u_int32_t pos;
736 int s;
737
738 s = spltty();
739 pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
740 ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
741 splx(s);
742 }
743
744 static void
745 ims332_load_curcmap(sc)
746 struct xcfb_softc *sc;
747 {
748 u_int8_t *cp = sc->sc_cursor.cc_color;
749 u_int32_t rgb;
750
751 /* cursor background */
752 rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
753 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
754
755 /* cursor foreground */
756 rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
757 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
758 }
759
760 static void
761 ims332_load_curshape(sc)
762 struct xcfb_softc *sc;
763 {
764 u_int i, img, msk, bits;
765 u_int8_t u, *ip, *mp;
766
767 ip = (u_int8_t *)sc->sc_cursor.cc_image;
768 mp = (u_int8_t *)sc->sc_cursor.cc_mask;
769
770 i = 0;
771 /* 64 pixel scan line is consisted with 8 halfword cursor ram */
772 while (i < sc->sc_cursor.cc_size.y * 8) {
773 /* pad right half 32 pixel when smaller than 33 */
774 if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
775 bits = 0;
776 else {
777 img = *ip++;
778 msk = *mp++;
779 img &= msk; /* cookie off image */
780 u = (msk & 0x0f) << 4 | (img & 0x0f);
781 bits = shuffle[u];
782 u = (msk & 0xf0) | (img & 0xf0) >> 4;
783 bits = (shuffle[u] << 8) | bits;
784 }
785 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
786 i += 1;
787 }
788 /* pad unoccupied scan lines */
789 while (i < CURSOR_MAX_SIZE * 8) {
790 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
791 i += 1;
792 }
793 }
794
795 static void
796 ims332_write_reg(regno, val)
797 int regno;
798 u_int32_t val;
799 {
800 caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
801 caddr_t low16 = (caddr_t)(ioasic_base + IMS332_WLOW) + (regno << 4);
802
803 *(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8;
804 *(volatile u_int16_t *)low16 = val;
805 }
806
807 #if 0
808 static u_int32_t
809 ims332_read_reg(regno)
810 int regno;
811 {
812 caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
813 caddr_t low16 = (caddr_t)(ioasic_base + IMS332_RLOW) + (regno << 4);
814 u_int v0, v1;
815
816 v1 = *(volatile u_int16_t *)high8;
817 v0 = *(volatile u_int16_t *)low16;
818 return (v1 & 0xff00) << 8 | v0;
819 }
820 #endif
821