xcfb.c revision 1.9 1 /* $NetBSD: xcfb.c,v 1.9 1999/04/30 00:44:11 nisimura Exp $ */
2
3 /*
4 * Copyright (c) 1998 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.9 1999/04/30 00:44:11 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 #include <vm/vm.h>
45
46 #include <machine/bus.h>
47 #include <machine/intr.h>
48
49 #include <dev/rcons/raster.h>
50 #include <dev/wscons/wsconsio.h>
51 #include <dev/wscons/wscons_raster.h>
52 #include <dev/wscons/wsdisplayvar.h>
53
54 #include <dev/tc/tcvar.h>
55 #include <dev/tc/ioasicreg.h>
56 #include <dev/ic/ims332reg.h>
57
58 #include <uvm/uvm_extern.h>
59
60 struct fb_devconfig {
61 vaddr_t dc_vaddr; /* memory space virtual base address */
62 paddr_t dc_paddr; /* memory space physical base address */
63 vsize_t dc_size; /* size of slot memory */
64 int dc_wid; /* width of frame buffer */
65 int dc_ht; /* height of frame buffer */
66 int dc_depth; /* depth, bits per pixel */
67 int dc_rowbytes; /* bytes in a FB scan line */
68 vaddr_t dc_videobase; /* base of flat frame buffer */
69 struct raster dc_raster; /* raster description */
70 struct rcons dc_rcons; /* raster blitter control info */
71 int dc_blanked; /* currently has video disabled */
72 };
73
74 struct hwcmap {
75 #define CMAP_SIZE 256 /* 256 R/G/B entries */
76 u_int8_t r[CMAP_SIZE];
77 u_int8_t g[CMAP_SIZE];
78 u_int8_t b[CMAP_SIZE];
79 };
80
81 struct hwcursor {
82 struct wsdisplay_curpos cc_pos;
83 struct wsdisplay_curpos cc_hot;
84 struct wsdisplay_curpos cc_size;
85 #define CURSOR_MAX_SIZE 64
86 u_int8_t cc_color[6];
87 u_int64_t cc_image[64 + 64];
88 };
89
90 #define XCFB_FB_OFFSET 0x2000000 /* from module's base */
91 #define XCFB_FB_SIZE 0x100000 /* frame buffer size */
92
93 #define IMS332_HIGH (IOASIC_SLOT_5_START)
94 #define IMS332_RLOW (IOASIC_SLOT_7_START)
95 #define IMS332_WLOW (IOASIC_SLOT_7_START + 0x20000)
96
97 struct xcfb_softc {
98 struct device sc_dev;
99 struct fb_devconfig *sc_dc; /* device configuration */
100 struct hwcmap sc_cmap; /* software copy of colormap */
101 struct hwcursor sc_cursor; /* software copy of cursor */
102 /* XXX MAXINE can take PMAG-DV virtical retrace interrupt XXX */
103 int nscreens;
104 /* cursor coordiate is located at upper-left corner */
105 int sc_csr; /* software copy of IMS332 CSR A */
106 };
107
108 int xcfbmatch __P((struct device *, struct cfdata *, void *));
109 void xcfbattach __P((struct device *, struct device *, void *));
110
111 struct cfattach xcfb_ca = {
112 sizeof(struct xcfb_softc), xcfbmatch, xcfbattach,
113 };
114
115 void xcfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
116 struct fb_devconfig xcfb_console_dc;
117 tc_addr_t xcfb_consaddr;
118
119
120 struct wsdisplay_emulops xcfb_emulops = {
121 rcons_cursor,
122 rcons_mapchar,
123 rcons_putchar,
124 rcons_copycols,
125 rcons_erasecols,
126 rcons_copyrows,
127 rcons_eraserows,
128 rcons_alloc_attr
129 };
130
131 struct wsscreen_descr xcfb_stdscreen = {
132 "std",
133 0, 0, /* will be filled in -- XXX shouldn't, it's global */
134 &xcfb_emulops,
135 0, 0,
136 0
137 };
138
139 const struct wsscreen_descr *_xcfb_scrlist[] = {
140 &xcfb_stdscreen,
141 };
142
143 struct wsscreen_list xcfb_screenlist = {
144 sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist
145 };
146
147 int xcfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
148 int xcfbmmap __P((void *, off_t, int));
149
150 int xcfb_alloc_screen __P((void *, const struct wsscreen_descr *,
151 void **, int *, int *, long *));
152 void xcfb_free_screen __P((void *, void *));
153 void xcfb_show_screen __P((void *, void *));
154
155 struct wsdisplay_accessops xcfb_accessops = {
156 xcfbioctl,
157 xcfbmmap,
158 xcfb_alloc_screen,
159 xcfb_free_screen,
160 xcfb_show_screen,
161 0 /* load_font */
162 };
163
164 int xcfb_cnattach __P((tc_addr_t));
165 int xcfbintr __P((void *));
166 void xcfbinit __P((struct fb_devconfig *));
167 void xcfb_screenblank __P((struct xcfb_softc *));
168
169 static int set_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *));
170 static int get_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *));
171 static int set_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *));
172 static int get_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *));
173 static void set_curpos __P((struct xcfb_softc *, struct wsdisplay_curpos *));
174 void ims332_loadcmap __P((struct hwcmap *));
175 void ims332_set_cursor __P((struct xcfb_softc *));
176 void ims332_set_curpos __P((struct xcfb_softc *));
177 void ims332_load_curcmap __P((struct xcfb_softc *));
178 void ims332_load_curshape __P((struct xcfb_softc *));
179 u_int32_t ims332_read_reg __P((int));
180 void ims332_write_reg __P((int, u_int32_t));
181
182 extern long ioasic_base; /* XXX */
183
184 /*
185 * Compose 2 bit/pixel cursor image.
186 * M M M M I I I I M I M I M I M I
187 * [ before ] [ after ]
188 * 3 2 1 0 3 2 1 0 3 3 2 2 1 1 0 0
189 * 7 6 5 4 7 6 5 4 7 7 6 6 5 5 4 4
190 */
191 const static u_int8_t shuffle[256] = {
192 0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15,
193 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55,
194 0x02, 0x03, 0x06, 0x07, 0x12, 0x13, 0x16, 0x17,
195 0x42, 0x43, 0x46, 0x47, 0x52, 0x53, 0x56, 0x57,
196 0x08, 0x09, 0x0c, 0x0d, 0x18, 0x19, 0x1c, 0x1d,
197 0x48, 0x49, 0x4c, 0x4d, 0x58, 0x59, 0x5c, 0x5d,
198 0x0a, 0x0b, 0x0e, 0x0f, 0x1a, 0x1b, 0x1e, 0x1f,
199 0x4a, 0x4b, 0x4e, 0x4f, 0x5a, 0x5b, 0x5e, 0x5f,
200 0x20, 0x21, 0x24, 0x25, 0x30, 0x31, 0x34, 0x35,
201 0x60, 0x61, 0x64, 0x65, 0x70, 0x71, 0x74, 0x75,
202 0x22, 0x23, 0x26, 0x27, 0x32, 0x33, 0x36, 0x37,
203 0x62, 0x63, 0x66, 0x67, 0x72, 0x73, 0x76, 0x77,
204 0x28, 0x29, 0x2c, 0x2d, 0x38, 0x39, 0x3c, 0x3d,
205 0x68, 0x69, 0x6c, 0x6d, 0x78, 0x79, 0x7c, 0x7d,
206 0x2a, 0x2b, 0x2e, 0x2f, 0x3a, 0x3b, 0x3e, 0x3f,
207 0x6a, 0x6b, 0x6e, 0x6f, 0x7a, 0x7b, 0x7e, 0x7f,
208 0x80, 0x81, 0x84, 0x85, 0x90, 0x91, 0x94, 0x95,
209 0xc0, 0xc1, 0xc4, 0xc5, 0xd0, 0xd1, 0xd4, 0xd5,
210 0x82, 0x83, 0x86, 0x87, 0x92, 0x93, 0x96, 0x97,
211 0xc2, 0xc3, 0xc6, 0xc7, 0xd2, 0xd3, 0xd6, 0xd7,
212 0x88, 0x89, 0x8c, 0x8d, 0x98, 0x99, 0x9c, 0x9d,
213 0xc8, 0xc9, 0xcc, 0xcd, 0xd8, 0xd9, 0xdc, 0xdd,
214 0x8a, 0x8b, 0x8e, 0x8f, 0x9a, 0x9b, 0x9e, 0x9f,
215 0xca, 0xcb, 0xce, 0xcf, 0xda, 0xdb, 0xde, 0xdf,
216 0xa0, 0xa1, 0xa4, 0xa5, 0xb0, 0xb1, 0xb4, 0xb5,
217 0xe0, 0xe1, 0xe4, 0xe5, 0xf0, 0xf1, 0xf4, 0xf5,
218 0xa2, 0xa3, 0xa6, 0xa7, 0xb2, 0xb3, 0xb6, 0xb7,
219 0xe2, 0xe3, 0xe6, 0xe7, 0xf2, 0xf3, 0xf6, 0xf7,
220 0xa8, 0xa9, 0xac, 0xad, 0xb8, 0xb9, 0xbc, 0xbd,
221 0xe8, 0xe9, 0xec, 0xed, 0xf8, 0xf9, 0xfc, 0xfd,
222 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf,
223 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff,
224 };
225
226 int
227 xcfbmatch(parent, match, aux)
228 struct device *parent;
229 struct cfdata *match;
230 void *aux;
231 {
232 struct tc_attach_args *ta = aux;
233
234 if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0)
235 return (0);
236
237 return (1);
238 }
239
240 void
241 xcfb_getdevconfig(dense_addr, dc)
242 tc_addr_t dense_addr;
243 struct fb_devconfig *dc;
244 {
245 struct raster *rap;
246 struct rcons *rcp;
247 int i;
248
249 dc->dc_vaddr = dense_addr;
250 dc->dc_paddr = MIPS_KSEG1_TO_PHYS(dc->dc_vaddr + XCFB_FB_OFFSET);
251
252 dc->dc_wid = 1024;
253 dc->dc_ht = 768;
254 dc->dc_depth = 8;
255 dc->dc_rowbytes = 1024;
256 dc->dc_videobase = dc->dc_vaddr + XCFB_FB_OFFSET;
257 dc->dc_blanked = 0;
258
259 /* initialize colormap and cursor resource */
260 xcfbinit(dc);
261
262 /* clear the screen */
263 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
264 *(u_int32_t *)(dc->dc_videobase + i) = 0;
265
266 /* initialize the raster */
267 rap = &dc->dc_raster;
268 rap->width = dc->dc_wid;
269 rap->height = dc->dc_ht;
270 rap->depth = dc->dc_depth;
271 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
272 rap->pixels = (u_int32_t *)dc->dc_videobase;
273
274 /* initialize the raster console blitter */
275 rcp = &dc->dc_rcons;
276 rcp->rc_sp = rap;
277 rcp->rc_crow = rcp->rc_ccol = -1;
278 rcp->rc_crowp = &rcp->rc_crow;
279 rcp->rc_ccolp = &rcp->rc_ccol;
280 rcons_init(rcp, 34, 80);
281
282 xcfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
283 xcfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
284 }
285
286 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 #if 1
295 struct hwcmap *cm;
296 int console;
297 #else
298 struct hwcmap *cm;
299 int console, i;
300 #endif
301
302 console = (ta->ta_addr == xcfb_consaddr);
303 if (console) {
304 sc->sc_dc = &xcfb_console_dc;
305 sc->nscreens = 1;
306 }
307 else {
308 sc->sc_dc = (struct fb_devconfig *)
309 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
310 xcfb_getdevconfig(ta->ta_addr, sc->sc_dc);
311 }
312 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
313 sc->sc_dc->dc_depth);
314
315 #if 1
316 cm = &sc->sc_cmap;
317 memset(cm, 255, sizeof(struct hwcmap)); /* XXX */
318 cm->r[0] = cm->g[0] = cm->b[0] = 0; /* XXX */
319 #else
320 cm = &sc->sc_cmap;
321 cm->r[0] = cm->g[0] = cm->b[0] = 0;
322 for (i = 1; i < CMAP_SIZE; i++) {
323 cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
324 }
325 #endif
326 sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
327
328 tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, xcfbintr, sc);
329
330 waa.console = console;
331 waa.scrdata = &xcfb_screenlist;
332 waa.accessops = &xcfb_accessops;
333 waa.accesscookie = sc;
334
335 config_found(self, &waa, wsemuldisplaydevprint);
336 }
337
338 int
339 xcfbioctl(v, cmd, data, flag, p)
340 void *v;
341 u_long cmd;
342 caddr_t data;
343 int flag;
344 struct proc *p;
345 {
346 struct xcfb_softc *sc = v;
347 struct fb_devconfig *dc = sc->sc_dc;
348 int turnoff, error;
349
350 switch (cmd) {
351 case WSDISPLAYIO_GTYPE:
352 *(u_int *)data = WSDISPLAY_TYPE_XCFB;
353 return (0);
354
355 case WSDISPLAYIO_GINFO:
356 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
357 wsd_fbip->height = sc->sc_dc->dc_ht;
358 wsd_fbip->width = sc->sc_dc->dc_wid;
359 wsd_fbip->depth = sc->sc_dc->dc_depth;
360 wsd_fbip->cmsize = CMAP_SIZE;
361 #undef fbt
362 return (0);
363
364 case WSDISPLAYIO_GETCMAP:
365 return get_cmap(sc, (struct wsdisplay_cmap *)data);
366
367 case WSDISPLAYIO_PUTCMAP:
368 error = set_cmap(sc, (struct wsdisplay_cmap *)data);
369 if (error == 0)
370 ims332_loadcmap(&sc->sc_cmap);
371 return (error);
372
373 case WSDISPLAYIO_SVIDEO:
374 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
375 if ((dc->dc_blanked == 0) ^ turnoff) {
376 dc->dc_blanked = turnoff;
377 xcfb_screenblank(sc);
378 }
379 return (0);
380
381 case WSDISPLAYIO_GVIDEO:
382 *(u_int *)data = dc->dc_blanked ?
383 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
384 return (0);
385
386 case WSDISPLAYIO_GCURPOS:
387 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
388 return (0);
389
390 case WSDISPLAYIO_SCURPOS:
391 set_curpos(sc, (struct wsdisplay_curpos *)data);
392 ims332_set_curpos(sc);
393 return (0);
394
395 case WSDISPLAYIO_GCURMAX:
396 ((struct wsdisplay_curpos *)data)->x =
397 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
398 return (0);
399
400 case WSDISPLAYIO_GCURSOR:
401 return get_cursor(sc, (struct wsdisplay_cursor *)data);
402
403 case WSDISPLAYIO_SCURSOR:
404 return set_cursor(sc, (struct wsdisplay_cursor *)data);
405 }
406 return ENOTTY;
407 }
408
409 int
410 xcfbmmap(v, offset, prot)
411 void *v;
412 off_t offset;
413 int prot;
414 {
415 struct xcfb_softc *sc = v;
416
417 if (offset >= XCFB_FB_SIZE || offset < 0)
418 return -1;
419 return mips_btop(sc->sc_dc->dc_paddr + offset);
420 }
421
422 int
423 xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
424 void *v;
425 const struct wsscreen_descr *type;
426 void **cookiep;
427 int *curxp, *curyp;
428 long *attrp;
429 {
430 struct xcfb_softc *sc = v;
431 long defattr;
432
433 if (sc->nscreens > 0)
434 return (ENOMEM);
435
436 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
437 *curxp = 0;
438 *curyp = 0;
439 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
440 *attrp = defattr;
441 sc->nscreens++;
442 return (0);
443 }
444
445 void
446 xcfb_free_screen(v, cookie)
447 void *v;
448 void *cookie;
449 {
450 struct xcfb_softc *sc = v;
451
452 if (sc->sc_dc == &xcfb_console_dc)
453 panic("xcfb_free_screen: console");
454
455 sc->nscreens--;
456 }
457
458 void
459 xcfb_show_screen(v, cookie)
460 void *v;
461 void *cookie;
462 {
463 }
464
465 int
466 xcfb_cnattach(addr)
467 tc_addr_t addr;
468 {
469 struct fb_devconfig *dcp = &xcfb_console_dc;
470 long defattr;
471
472 xcfb_getdevconfig(addr, dcp);
473
474 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
475
476 wsdisplay_cnattach(&xcfb_stdscreen, &dcp->dc_rcons,
477 0, 0, defattr);
478 xcfb_consaddr = addr;
479 return (0);
480 }
481
482 int
483 xcfbintr(v)
484 void *v;
485 {
486 int intr;
487
488 intr = *(u_int32_t *)(ioasic_base + IOASIC_INTR);
489 intr &= ~XINE_INTR_VINT;
490 *(u_int32_t *)(ioasic_base + IOASIC_INTR) = intr;
491 return 1;
492 }
493
494 void
495 xcfbinit(dc)
496 struct fb_devconfig *dc;
497 {
498 u_int32_t csr;
499 int i;
500
501 csr = *(u_int32_t *)(ioasic_base + IOASIC_CSR);
502 csr &= ~XINE_CSR_VDAC_ENABLE;
503 *(u_int32_t *)(ioasic_base + IOASIC_CSR) = csr;
504 DELAY(50);
505 csr |= XINE_CSR_VDAC_ENABLE;
506 *(u_int32_t *)(ioasic_base + IOASIC_CSR) = csr;
507 DELAY(50);
508 ims332_write_reg(IMS332_REG_BOOT, 0x2c);
509 ims332_write_reg(IMS332_REG_CSR_A,
510 IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
511 ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
512 ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
513 ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
514 ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
515 ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
516 ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
517 ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
518 ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
519 ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
520 ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
521 ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
522 ims332_write_reg(IMS332_REG_LINE_START, 0x10);
523 ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
524 ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
525 ims332_write_reg(IMS332_REG_CSR_A,
526 IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
527
528 /* build sane colormap */
529 ims332_write_reg(IMS332_REG_LUT_BASE, 0);
530 for (i = 1; i < CMAP_SIZE; i++)
531 ims332_write_reg(IMS332_REG_LUT_BASE + i, 0xffffff);
532
533 /* clear out cursor image */
534 for (i = 0; i < 512; i++)
535 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
536
537 /*
538 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
539 * cursor image. LUT_1 for mask color, while LUT_2 for
540 * image color. LUT_0 will be never used.
541 */
542 ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
543 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
544 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
545 }
546
547 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 void
686 ims332_loadcmap(cm)
687 struct hwcmap *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 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 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 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 halfward 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 u_int32_t
764 ims332_read_reg(regno)
765 int regno;
766 {
767 caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
768 caddr_t low16 = (caddr_t)(ioasic_base + IMS332_RLOW) + (regno << 4);
769 u_int v0, v1;
770
771 v1 = *(volatile u_int16_t *)high8;
772 v0 = *(volatile u_int16_t *)low16;
773 return (v1 & 0xff00) << 8 | v0;
774 }
775
776 void
777 ims332_write_reg(regno, val)
778 int regno;
779 u_int32_t val;
780 {
781 caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
782 caddr_t low16 = (caddr_t)(ioasic_base + IMS332_WLOW) + (regno << 4);
783
784 *(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8;
785 *(volatile u_int16_t *)low16 = val;
786 }
787