xcfb.c revision 1.22 1 /* $NetBSD: xcfb.c,v 1.22 2001/04/09 16:10:06 nathanw 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.22 2001/04/09 16:10:06 nathanw 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 vertical retrace interrupt XXX */
105 int nscreens;
106 /* cursor coordinate 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 struct hwcmap256 *cm;
295 const u_int8_t *p;
296 int console, index;
297
298 console = (ta->ta_addr == xcfb_consaddr);
299 if (console) {
300 sc->sc_dc = &xcfb_console_dc;
301 sc->nscreens = 1;
302 }
303 else {
304 sc->sc_dc = (struct fb_devconfig *)
305 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
306 xcfb_getdevconfig(ta->ta_addr, sc->sc_dc);
307 }
308 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
309 sc->sc_dc->dc_depth);
310
311 cm = &sc->sc_cmap;
312 p = rasops_cmap;
313 for (index = 0; index < CMAP_SIZE; index++, p += 3) {
314 cm->r[index] = p[0];
315 cm->g[index] = p[1];
316 cm->b[index] = p[2];
317 }
318
319 sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
320
321 tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, xcfbintr, sc);
322
323 waa.console = console;
324 waa.scrdata = &xcfb_screenlist;
325 waa.accessops = &xcfb_accessops;
326 waa.accesscookie = sc;
327
328 config_found(self, &waa, wsemuldisplaydevprint);
329 }
330
331 int
332 xcfb_cnattach()
333 {
334 tc_addr_t addr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START);
335 struct fb_devconfig *dcp = &xcfb_console_dc;
336 long defattr;
337
338 xcfb_getdevconfig(addr, dcp);
339 (*dcp->rinfo.ri_ops.alloc_attr)(&dcp->rinfo, 0, 0, 0, &defattr);
340 wsdisplay_cnattach(&xcfb_stdscreen, &dcp->rinfo, 0, 0, defattr);
341 xcfb_consaddr = addr;
342 return (0);
343 }
344
345 static void
346 xcfbinit(dc)
347 struct fb_devconfig *dc;
348 {
349 u_int32_t csr;
350 const u_int8_t *p;
351 int i;
352
353 csr = *(u_int32_t *)(ioasic_base + IOASIC_CSR);
354 csr &= ~XINE_CSR_VDAC_ENABLE;
355 *(u_int32_t *)(ioasic_base + IOASIC_CSR) = csr;
356 DELAY(50);
357 csr |= XINE_CSR_VDAC_ENABLE;
358 *(u_int32_t *)(ioasic_base + IOASIC_CSR) = csr;
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 fb_devconfig *dc = sc->sc_dc;
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 = sc->sc_dc->dc_ht;
423 wsd_fbip->width = sc->sc_dc->dc_wid;
424 wsd_fbip->depth = sc->sc_dc->dc_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 ((dc->dc_blanked == 0) ^ turnoff) {
441 dc->dc_blanked = turnoff;
442 xcfb_screenblank(sc);
443 }
444 return (0);
445
446 case WSDISPLAYIO_GVIDEO:
447 *(u_int *)data = dc->dc_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 return (ENOTTY);
472 }
473
474 static paddr_t
475 xcfbmmap(v, offset, prot)
476 void *v;
477 off_t offset;
478 int prot;
479 {
480 struct xcfb_softc *sc = v;
481
482 if (offset >= XCFB_FB_SIZE || offset < 0)
483 return (-1);
484 return mips_btop(sc->sc_dc->dc_paddr + offset);
485 }
486
487 static int
488 xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
489 void *v;
490 const struct wsscreen_descr *type;
491 void **cookiep;
492 int *curxp, *curyp;
493 long *attrp;
494 {
495 struct xcfb_softc *sc = v;
496 long defattr;
497
498 if (sc->nscreens > 0)
499 return (ENOMEM);
500
501 *cookiep = &sc->sc_dc->rinfo; /* one and only for now */
502 *curxp = 0;
503 *curyp = 0;
504 (*sc->sc_dc->rinfo.ri_ops.alloc_attr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr);
505 *attrp = defattr;
506 sc->nscreens++;
507 return (0);
508 }
509
510 static void
511 xcfb_free_screen(v, cookie)
512 void *v;
513 void *cookie;
514 {
515 struct xcfb_softc *sc = v;
516
517 if (sc->sc_dc == &xcfb_console_dc)
518 panic("xcfb_free_screen: console");
519
520 sc->nscreens--;
521 }
522
523 static int
524 xcfb_show_screen(v, cookie, waitok, cb, cbarg)
525 void *v;
526 void *cookie;
527 int waitok;
528 void (*cb) __P((void *, int, int));
529 void *cbarg;
530 {
531
532 return (0);
533 }
534
535 static int
536 xcfbintr(v)
537 void *v;
538 {
539 int intr;
540
541 intr = *(u_int32_t *)(ioasic_base + IOASIC_INTR);
542 intr &= ~XINE_INTR_VINT;
543 *(u_int32_t *)(ioasic_base + IOASIC_INTR) = intr;
544 return (1);
545 }
546
547 static void
548 xcfb_screenblank(sc)
549 struct xcfb_softc *sc;
550 {
551 if (sc->sc_dc->dc_blanked)
552 sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK;
553 else
554 sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK;
555 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
556 }
557
558 static int
559 get_cmap(sc, p)
560 struct xcfb_softc *sc;
561 struct wsdisplay_cmap *p;
562 {
563 u_int index = p->index, count = p->count;
564
565 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
566 return (EINVAL);
567
568 if (!uvm_useracc(p->red, count, B_WRITE) ||
569 !uvm_useracc(p->green, count, B_WRITE) ||
570 !uvm_useracc(p->blue, count, B_WRITE))
571 return (EFAULT);
572
573 copyout(&sc->sc_cmap.r[index], p->red, count);
574 copyout(&sc->sc_cmap.g[index], p->green, count);
575 copyout(&sc->sc_cmap.b[index], p->blue, count);
576
577 return (0);
578 }
579
580 static int
581 set_cmap(sc, p)
582 struct xcfb_softc *sc;
583 struct wsdisplay_cmap *p;
584 {
585 u_int index = p->index, count = p->count;
586
587 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
588 return (EINVAL);
589
590 if (!uvm_useracc(p->red, count, B_READ) ||
591 !uvm_useracc(p->green, count, B_READ) ||
592 !uvm_useracc(p->blue, count, B_READ))
593 return (EFAULT);
594
595 copyin(p->red, &sc->sc_cmap.r[index], count);
596 copyin(p->green, &sc->sc_cmap.g[index], count);
597 copyin(p->blue, &sc->sc_cmap.b[index], count);
598
599 return (0);
600 }
601
602 static int
603 set_cursor(sc, p)
604 struct xcfb_softc *sc;
605 struct wsdisplay_cursor *p;
606 {
607 #define cc (&sc->sc_cursor)
608 int v, index, count;
609
610 v = p->which;
611 if (v & WSDISPLAY_CURSOR_DOCMAP) {
612 index = p->cmap.index;
613 count = p->cmap.count;
614
615 if (index >= 2 || index + count > 2)
616 return (EINVAL);
617 if (!uvm_useracc(p->cmap.red, count, B_READ) ||
618 !uvm_useracc(p->cmap.green, count, B_READ) ||
619 !uvm_useracc(p->cmap.blue, count, B_READ))
620 return (EFAULT);
621
622 copyin(p->cmap.red, &cc->cc_color[index], count);
623 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
624 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
625 ims332_load_curcmap(sc);
626 }
627 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
628 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
629 return (EINVAL);
630 count = ((p->size.x < 33) ? 4 : 8) * p->size.y;
631 if (!uvm_useracc(p->image, count, B_READ) ||
632 !uvm_useracc(p->mask, count, B_READ))
633 return (EFAULT);
634 cc->cc_size = p->size;
635 memset(cc->cc_image, 0, sizeof cc->cc_image);
636 copyin(p->image, cc->cc_image, count);
637 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count);
638 ims332_load_curshape(sc);
639 }
640 if (v & WSDISPLAY_CURSOR_DOCUR) {
641 cc->cc_hot = p->hot;
642 if (p->enable)
643 sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
644 else
645 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
646 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
647 }
648 if (v & WSDISPLAY_CURSOR_DOPOS) {
649 set_curpos(sc, &p->pos);
650 ims332_set_curpos(sc);
651 }
652
653 return (0);
654 #undef cc
655 }
656
657 static int
658 get_cursor(sc, p)
659 struct xcfb_softc *sc;
660 struct wsdisplay_cursor *p;
661 {
662 return (ENOTTY); /* XXX */
663 }
664
665 static void
666 set_curpos(sc, curpos)
667 struct xcfb_softc *sc;
668 struct wsdisplay_curpos *curpos;
669 {
670 struct fb_devconfig *dc = sc->sc_dc;
671 int x = curpos->x, y = curpos->y;
672
673 if (y < 0)
674 y = 0;
675 else if (y > dc->dc_ht)
676 y = dc->dc_ht;
677 if (x < 0)
678 x = 0;
679 else if (x > dc->dc_wid)
680 x = dc->dc_wid;
681 sc->sc_cursor.cc_pos.x = x;
682 sc->sc_cursor.cc_pos.y = y;
683 }
684
685 static void
686 ims332_loadcmap(cm)
687 struct hwcmap256 *cm;
688 {
689 int i;
690 u_int32_t rgb;
691
692 for (i = 0; i < CMAP_SIZE; i++) {
693 rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
694 ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
695 }
696 }
697
698 static void
699 ims332_set_curpos(sc)
700 struct xcfb_softc *sc;
701 {
702 struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
703 u_int32_t pos;
704 int s;
705
706 s = spltty();
707 pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
708 ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
709 splx(s);
710 }
711
712 static void
713 ims332_load_curcmap(sc)
714 struct xcfb_softc *sc;
715 {
716 u_int8_t *cp = sc->sc_cursor.cc_color;
717 u_int32_t rgb;
718
719 /* cursor background */
720 rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
721 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
722
723 /* cursor foreground */
724 rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
725 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
726 }
727
728 static void
729 ims332_load_curshape(sc)
730 struct xcfb_softc *sc;
731 {
732 unsigned i, img, msk, bits;
733 u_int8_t u, *ip, *mp;
734
735 ip = (u_int8_t *)sc->sc_cursor.cc_image;
736 mp = (u_int8_t *)(sc->sc_cursor.cc_image+CURSOR_MAX_SIZE);
737
738 i = 0;
739 /* 64 pixel scan line is consisted with 8 halfword cursor ram */
740 while (i < sc->sc_cursor.cc_size.y * 8) {
741 /* pad right half 32 pixel when smaller than 33 */
742 if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
743 bits = 0;
744 else {
745 img = *ip++;
746 msk = *mp++;
747 img &= msk; /* cookie off image */
748 u = (msk & 0x0f) << 4 | (img & 0x0f);
749 bits = shuffle[u];
750 u = (msk & 0xf0) | (img & 0xf0) >> 4;
751 bits = (shuffle[u] << 8) | bits;
752 }
753 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
754 i += 1;
755 }
756 /* pad unoccupied scan lines */
757 while (i < CURSOR_MAX_SIZE * 8) {
758 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
759 i += 1;
760 }
761 }
762
763 static void
764 ims332_write_reg(regno, val)
765 int regno;
766 u_int32_t val;
767 {
768 caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
769 caddr_t low16 = (caddr_t)(ioasic_base + IMS332_WLOW) + (regno << 4);
770
771 *(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8;
772 *(volatile u_int16_t *)low16 = val;
773 }
774
775 #if 0
776 static u_int32_t
777 ims332_read_reg(regno)
778 int regno;
779 {
780 caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
781 caddr_t low16 = (caddr_t)(ioasic_base + IMS332_RLOW) + (regno << 4);
782 u_int v0, v1;
783
784 v1 = *(volatile u_int16_t *)high8;
785 v0 = *(volatile u_int16_t *)low16;
786 return (v1 & 0xff00) << 8 | v0;
787 }
788 #endif
789