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