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