xcfb.c revision 1.7 1 /* $NetBSD: xcfb.c,v 1.7 1999/03/24 05:51:22 mrg 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.7 1999/03/24 05:51:22 mrg 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 #include <machine/autoconf.h>
54
55 #include <dev/tc/tcvar.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_ADDRESS 0xbc140000
94 #define IMS332_RPTR 0xbc1c0000
95 #define IMS332_WPTR 0xbc1e0000
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 };
106
107 int xcfbmatch __P((struct device *, struct cfdata *, void *));
108 void xcfbattach __P((struct device *, struct device *, void *));
109
110 struct cfattach xcfb_ca = {
111 sizeof(struct xcfb_softc), xcfbmatch, xcfbattach,
112 };
113
114 void xcfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
115 struct fb_devconfig xcfb_console_dc;
116 tc_addr_t xcfb_consaddr;
117
118 struct wsdisplay_emulops xcfb_emulops = {
119 rcons_cursor,
120 rcons_mapchar,
121 rcons_putchar,
122 rcons_copycols,
123 rcons_erasecols,
124 rcons_copyrows,
125 rcons_eraserows,
126 rcons_alloc_attr
127 };
128
129 struct wsscreen_descr xcfb_stdscreen = {
130 "std",
131 0, 0, /* will be filled in -- XXX shouldn't, it's global */
132 &xcfb_emulops,
133 0, 0,
134 0
135 };
136
137 const struct wsscreen_descr *_xcfb_scrlist[] = {
138 &xcfb_stdscreen,
139 };
140
141 struct wsscreen_list xcfb_screenlist = {
142 sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist
143 };
144
145 int xcfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
146 int xcfbmmap __P((void *, off_t, int));
147
148 int xcfb_alloc_screen __P((void *, const struct wsscreen_descr *,
149 void **, int *, int *, long *));
150 void xcfb_free_screen __P((void *, void *));
151 void xcfb_show_screen __P((void *, void *));
152
153 struct wsdisplay_accessops xcfb_accessops = {
154 xcfbioctl,
155 xcfbmmap,
156 xcfb_alloc_screen,
157 xcfb_free_screen,
158 xcfb_show_screen,
159 0 /* load_font */
160 };
161
162 int xcfb_cnattach __P((tc_addr_t));
163 void xcfbinit __P((struct fb_devconfig *));
164 void xcfb_screenblank __P((struct xcfb_softc *));
165
166 static int set_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *));
167 static int get_cmap __P((struct xcfb_softc *, struct wsdisplay_cmap *));
168 static int set_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *));
169 static int get_cursor __P((struct xcfb_softc *, struct wsdisplay_cursor *));
170 static void set_curpos __P((struct xcfb_softc *, struct wsdisplay_curpos *));
171 void ims332_loadcmap __P((struct hwcmap *));
172 void ims332_set_cursor __P((struct xcfb_softc *));
173 void ims332_set_curpos __P((struct xcfb_softc *));
174 void ims332_load_curcmap __P((struct xcfb_softc *));
175 void ims332_load_curshape __P((struct xcfb_softc *));
176 u_int32_t ims332_read_reg __P((int));
177 void ims332_write_reg __P((int, u_int32_t));
178
179 /*
180 * Compose 2 bit/pixel cursor image.
181 * M M M M I I I I M I M I M I M I
182 * [ before ] [ after ]
183 * 3 2 1 0 3 2 1 0 3 3 2 2 1 1 0 0
184 * 7 6 5 4 7 6 5 4 7 7 6 6 5 5 4 4
185 */
186 const static u_int8_t shuffle[256] = {
187 0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15,
188 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55,
189 0x02, 0x03, 0x06, 0x07, 0x12, 0x13, 0x16, 0x17,
190 0x42, 0x43, 0x46, 0x47, 0x52, 0x53, 0x56, 0x57,
191 0x08, 0x09, 0x0c, 0x0d, 0x18, 0x19, 0x1c, 0x1d,
192 0x48, 0x49, 0x4c, 0x4d, 0x58, 0x59, 0x5c, 0x5d,
193 0x0a, 0x0b, 0x0e, 0x0f, 0x1a, 0x1b, 0x1e, 0x1f,
194 0x4a, 0x4b, 0x4e, 0x4f, 0x5a, 0x5b, 0x5e, 0x5f,
195 0x20, 0x21, 0x24, 0x25, 0x30, 0x31, 0x34, 0x35,
196 0x60, 0x61, 0x64, 0x65, 0x70, 0x71, 0x74, 0x75,
197 0x22, 0x23, 0x26, 0x27, 0x32, 0x33, 0x36, 0x37,
198 0x62, 0x63, 0x66, 0x67, 0x72, 0x73, 0x76, 0x77,
199 0x28, 0x29, 0x2c, 0x2d, 0x38, 0x39, 0x3c, 0x3d,
200 0x68, 0x69, 0x6c, 0x6d, 0x78, 0x79, 0x7c, 0x7d,
201 0x2a, 0x2b, 0x2e, 0x2f, 0x3a, 0x3b, 0x3e, 0x3f,
202 0x6a, 0x6b, 0x6e, 0x6f, 0x7a, 0x7b, 0x7e, 0x7f,
203 0x80, 0x81, 0x84, 0x85, 0x90, 0x91, 0x94, 0x95,
204 0xc0, 0xc1, 0xc4, 0xc5, 0xd0, 0xd1, 0xd4, 0xd5,
205 0x82, 0x83, 0x86, 0x87, 0x92, 0x93, 0x96, 0x97,
206 0xc2, 0xc3, 0xc6, 0xc7, 0xd2, 0xd3, 0xd6, 0xd7,
207 0x88, 0x89, 0x8c, 0x8d, 0x98, 0x99, 0x9c, 0x9d,
208 0xc8, 0xc9, 0xcc, 0xcd, 0xd8, 0xd9, 0xdc, 0xdd,
209 0x8a, 0x8b, 0x8e, 0x8f, 0x9a, 0x9b, 0x9e, 0x9f,
210 0xca, 0xcb, 0xce, 0xcf, 0xda, 0xdb, 0xde, 0xdf,
211 0xa0, 0xa1, 0xa4, 0xa5, 0xb0, 0xb1, 0xb4, 0xb5,
212 0xe0, 0xe1, 0xe4, 0xe5, 0xf0, 0xf1, 0xf4, 0xf5,
213 0xa2, 0xa3, 0xa6, 0xa7, 0xb2, 0xb3, 0xb6, 0xb7,
214 0xe2, 0xe3, 0xe6, 0xe7, 0xf2, 0xf3, 0xf6, 0xf7,
215 0xa8, 0xa9, 0xac, 0xad, 0xb8, 0xb9, 0xbc, 0xbd,
216 0xe8, 0xe9, 0xec, 0xed, 0xf8, 0xf9, 0xfc, 0xfd,
217 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf,
218 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff,
219 };
220
221 int
222 xcfbmatch(parent, match, aux)
223 struct device *parent;
224 struct cfdata *match;
225 void *aux;
226 {
227 struct tc_attach_args *ta = aux;
228
229 if (strncmp("PMAG-DV ", ta->ta_modname, TC_ROM_LLEN) != 0)
230 return (0);
231
232 return (1);
233 }
234
235 void
236 xcfb_getdevconfig(dense_addr, dc)
237 tc_addr_t dense_addr;
238 struct fb_devconfig *dc;
239 {
240 struct raster *rap;
241 struct rcons *rcp;
242 int i;
243
244 dc->dc_vaddr = dense_addr;
245 dc->dc_paddr = MIPS_KSEG1_TO_PHYS(dc->dc_vaddr + XCFB_FB_OFFSET);
246
247 dc->dc_wid = 1024;
248 dc->dc_ht = 768;
249 dc->dc_depth = 8;
250 dc->dc_rowbytes = 1024;
251 dc->dc_videobase = dc->dc_vaddr + XCFB_FB_OFFSET;
252 dc->dc_blanked = 0;
253
254 /* initialize colormap and cursor resource */
255 xcfbinit(dc);
256
257 /* clear the screen */
258 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
259 *(u_int32_t *)(dc->dc_videobase + i) = 0;
260
261 /* initialize the raster */
262 rap = &dc->dc_raster;
263 rap->width = dc->dc_wid;
264 rap->height = dc->dc_ht;
265 rap->depth = dc->dc_depth;
266 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
267 rap->pixels = (u_int32_t *)dc->dc_videobase;
268
269 /* initialize the raster console blitter */
270 rcp = &dc->dc_rcons;
271 rcp->rc_sp = rap;
272 rcp->rc_crow = rcp->rc_ccol = -1;
273 rcp->rc_crowp = &rcp->rc_crow;
274 rcp->rc_ccolp = &rcp->rc_ccol;
275 rcons_init(rcp, 34, 80);
276
277 xcfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
278 xcfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
279 }
280
281 void
282 xcfbattach(parent, self, aux)
283 struct device *parent, *self;
284 void *aux;
285 {
286 struct xcfb_softc *sc = (struct xcfb_softc *)self;
287 struct tc_attach_args *ta = aux;
288 struct wsemuldisplaydev_attach_args waa;
289 struct hwcmap *cm;
290 int console, i;
291
292 console = (ta->ta_addr == xcfb_consaddr);
293 if (console) {
294 sc->sc_dc = &xcfb_console_dc;
295 sc->nscreens = 1;
296 }
297 else {
298 sc->sc_dc = (struct fb_devconfig *)
299 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
300 xcfb_getdevconfig(ta->ta_addr, sc->sc_dc);
301 }
302 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
303 sc->sc_dc->dc_depth);
304
305 cm = &sc->sc_cmap;
306 cm->r[0] = cm->g[0] = cm->b[0] = 0;
307 for (i = 1; i < CMAP_SIZE; i++) {
308 cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
309 }
310
311 /* PMAG-DV emits no interrupt */
312
313 waa.console = console;
314 waa.scrdata = &xcfb_screenlist;
315 waa.accessops = &xcfb_accessops;
316 waa.accesscookie = sc;
317
318 config_found(self, &waa, wsemuldisplaydevprint);
319 }
320
321 int
322 xcfbioctl(v, cmd, data, flag, p)
323 void *v;
324 u_long cmd;
325 caddr_t data;
326 int flag;
327 struct proc *p;
328 {
329 struct xcfb_softc *sc = v;
330 struct fb_devconfig *dc = sc->sc_dc;
331 int turnoff, error;
332
333 switch (cmd) {
334 case WSDISPLAYIO_GTYPE:
335 *(u_int *)data = WSDISPLAY_TYPE_XCFB;
336 return (0);
337
338 case WSDISPLAYIO_GINFO:
339 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
340 wsd_fbip->height = sc->sc_dc->dc_ht;
341 wsd_fbip->width = sc->sc_dc->dc_wid;
342 wsd_fbip->depth = sc->sc_dc->dc_depth;
343 wsd_fbip->cmsize = CMAP_SIZE;
344 #undef fbt
345 return (0);
346
347 case WSDISPLAYIO_GETCMAP:
348 return get_cmap(sc, (struct wsdisplay_cmap *)data);
349
350 case WSDISPLAYIO_PUTCMAP:
351 error = set_cmap(sc, (struct wsdisplay_cmap *)data);
352 if (error == 0)
353 ims332_loadcmap(&sc->sc_cmap);
354 return (error);
355
356 case WSDISPLAYIO_SVIDEO:
357 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
358 if ((dc->dc_blanked == 0) ^ turnoff) {
359 dc->dc_blanked = turnoff;
360 xcfb_screenblank(sc);
361 }
362 return (0);
363
364 case WSDISPLAYIO_GVIDEO:
365 *(u_int *)data = dc->dc_blanked ?
366 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
367 return (0);
368
369 case WSDISPLAYIO_GCURPOS:
370 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
371 return (0);
372
373 case WSDISPLAYIO_SCURPOS:
374 set_curpos(sc, (struct wsdisplay_curpos *)data);
375 ims332_set_curpos(sc);
376 return (0);
377
378 case WSDISPLAYIO_GCURMAX:
379 ((struct wsdisplay_curpos *)data)->x =
380 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
381 return (0);
382
383 case WSDISPLAYIO_GCURSOR:
384 return get_cursor(sc, (struct wsdisplay_cursor *)data);
385
386 case WSDISPLAYIO_SCURSOR:
387 return set_cursor(sc, (struct wsdisplay_cursor *)data);
388 }
389 return ENOTTY;
390 }
391
392 int
393 xcfbmmap(v, offset, prot)
394 void *v;
395 off_t offset;
396 int prot;
397 {
398 struct xcfb_softc *sc = v;
399
400 if (offset >= XCFB_FB_SIZE || offset < 0)
401 return -1;
402 return mips_btop(sc->sc_dc->dc_paddr + offset);
403 }
404
405 int
406 xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
407 void *v;
408 const struct wsscreen_descr *type;
409 void **cookiep;
410 int *curxp, *curyp;
411 long *attrp;
412 {
413 struct xcfb_softc *sc = v;
414 long defattr;
415
416 if (sc->nscreens > 0)
417 return (ENOMEM);
418
419 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
420 *curxp = 0;
421 *curyp = 0;
422 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
423 *attrp = defattr;
424 sc->nscreens++;
425 return (0);
426 }
427
428 void
429 xcfb_free_screen(v, cookie)
430 void *v;
431 void *cookie;
432 {
433 struct xcfb_softc *sc = v;
434
435 if (sc->sc_dc == &xcfb_console_dc)
436 panic("xcfb_free_screen: console");
437
438 sc->nscreens--;
439 }
440
441 void
442 xcfb_show_screen(v, cookie)
443 void *v;
444 void *cookie;
445 {
446 }
447
448 int
449 xcfb_cnattach(addr)
450 tc_addr_t addr;
451 {
452 struct fb_devconfig *dcp = &xcfb_console_dc;
453 long defattr;
454
455 xcfb_getdevconfig(addr, dcp);
456
457 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
458
459 wsdisplay_cnattach(&xcfb_stdscreen, &dcp->dc_rcons,
460 0, 0, defattr);
461 xcfb_consaddr = addr;
462 return(0);
463 }
464
465 void
466 xcfbinit(dc)
467 struct fb_devconfig *dc;
468 {
469 u_int32_t csr;
470 int i;
471
472 csr = IMS332_BPP_8 | IMS332_CSR_A_DMA_DISABLE
473 | IMS332_CSR_A_VTG_ENABLE | IMS332_CSR_A_DISABLE_CURSOR;
474 ims332_write_reg(IMS332_REG_CSR_A, csr);
475
476 ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
477
478 /* build sane colormap */
479 ims332_write_reg(IMS332_REG_LUT_BASE, 0);
480 for (i = 1; i < CMAP_SIZE; i++)
481 ims332_write_reg(IMS332_REG_LUT_BASE + i, 0xffffff);
482
483 /* clear out cursor image */
484 for (i = 0; i < 512; i++)
485 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
486
487 /*
488 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
489 * cursor image. LUT_1 for mask color, while LUT_2 for
490 * image color. LUT_0 will be never used.
491 */
492 ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
493 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
494 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
495 }
496
497 void
498 xcfb_screenblank(sc)
499 struct xcfb_softc *sc;
500 {
501 struct fb_devconfig *dc = sc->sc_dc;
502 u_int16_t csr;
503
504 if (dc->dc_blanked) {
505 /* blank screen */
506 ims332_write_reg(IMS332_REG_LUT_BASE, 0);
507 ims332_write_reg(IMS332_REG_COLOR_MASK, 0);
508 csr = ims332_read_reg(IMS332_REG_CSR_A);
509 csr |= IMS332_CSR_A_DISABLE_CURSOR;
510 ims332_write_reg(IMS332_REG_CSR_A, csr);
511 }
512 else {
513 /* restore current colormap */
514 ims332_loadcmap(&sc->sc_cmap);
515 /* turnon hardware cursor */
516 csr = ims332_read_reg(IMS332_REG_CSR_A);
517 csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
518 ims332_write_reg(IMS332_REG_CSR_A, csr);
519 }
520 }
521
522 static int
523 get_cmap(sc, p)
524 struct xcfb_softc *sc;
525 struct wsdisplay_cmap *p;
526 {
527 u_int index = p->index, count = p->count;
528
529 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
530 return (EINVAL);
531
532 if (!uvm_useracc(p->red, count, B_WRITE) ||
533 !uvm_useracc(p->green, count, B_WRITE) ||
534 !uvm_useracc(p->blue, count, B_WRITE))
535 return (EFAULT);
536
537 copyout(&sc->sc_cmap.r[index], p->red, count);
538 copyout(&sc->sc_cmap.g[index], p->green, count);
539 copyout(&sc->sc_cmap.b[index], p->blue, count);
540
541 return (0);
542 }
543
544 static int
545 set_cmap(sc, p)
546 struct xcfb_softc *sc;
547 struct wsdisplay_cmap *p;
548 {
549 u_int index = p->index, count = p->count;
550
551 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
552 return (EINVAL);
553
554 if (!uvm_useracc(p->red, count, B_READ) ||
555 !uvm_useracc(p->green, count, B_READ) ||
556 !uvm_useracc(p->blue, count, B_READ))
557 return (EFAULT);
558
559 copyin(p->red, &sc->sc_cmap.r[index], count);
560 copyin(p->green, &sc->sc_cmap.g[index], count);
561 copyin(p->blue, &sc->sc_cmap.b[index], count);
562
563 return (0);
564 }
565
566 static int
567 set_cursor(sc, p)
568 struct xcfb_softc *sc;
569 struct wsdisplay_cursor *p;
570 {
571 #define cc (&sc->sc_cursor)
572 int v, index, count;
573 u_int32_t csr;
574
575 v = p->which;
576 if (v & WSDISPLAY_CURSOR_DOCMAP) {
577 index = p->cmap.index;
578 count = p->cmap.count;
579
580 if (index >= 2 || index + count > 2)
581 return (EINVAL);
582 if (!uvm_useracc(p->cmap.red, count, B_READ) ||
583 !uvm_useracc(p->cmap.green, count, B_READ) ||
584 !uvm_useracc(p->cmap.blue, count, B_READ))
585 return (EFAULT);
586
587 copyin(p->cmap.red, &cc->cc_color[index], count);
588 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
589 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
590 ims332_load_curcmap(sc);
591 }
592 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
593 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
594 return (EINVAL);
595 count = ((p->size.x < 33) ? 4 : 8) * p->size.y;
596 if (!uvm_useracc(p->image, count, B_READ) ||
597 !uvm_useracc(p->mask, count, B_READ))
598 return (EFAULT);
599 cc->cc_size = p->size;
600 memset(cc->cc_image, 0, sizeof cc->cc_image);
601 copyin(p->image, cc->cc_image, count);
602 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count);
603 ims332_load_curshape(sc);
604 }
605 if (v & WSDISPLAY_CURSOR_DOCUR) {
606 cc->cc_hot = p->hot;
607 csr = ims332_read_reg(IMS332_REG_CSR_A);
608 if (p->enable)
609 csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
610 else
611 csr |= IMS332_CSR_A_DISABLE_CURSOR;
612 ims332_write_reg(IMS332_REG_CSR_A, csr);
613 }
614 if (v & WSDISPLAY_CURSOR_DOPOS) {
615 set_curpos(sc, &p->pos);
616 ims332_set_curpos(sc);
617 }
618
619 return (0);
620 #undef cc
621 }
622
623 static int
624 get_cursor(sc, p)
625 struct xcfb_softc *sc;
626 struct wsdisplay_cursor *p;
627 {
628 return (ENOTTY); /* XXX */
629 }
630
631 static void
632 set_curpos(sc, curpos)
633 struct xcfb_softc *sc;
634 struct wsdisplay_curpos *curpos;
635 {
636 struct fb_devconfig *dc = sc->sc_dc;
637 int x = curpos->x, y = curpos->y;
638
639 if (y < 0)
640 y = 0;
641 else if (y > dc->dc_ht)
642 y = dc->dc_ht;
643 if (x < 0)
644 x = 0;
645 else if (x > dc->dc_wid)
646 x = dc->dc_wid;
647 sc->sc_cursor.cc_pos.x = x;
648 sc->sc_cursor.cc_pos.y = y;
649 }
650
651 void
652 ims332_loadcmap(cm)
653 struct hwcmap *cm;
654 {
655 int i;
656 u_int32_t rgb;
657
658 for (i = 0; i < CMAP_SIZE; i++) {
659 rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
660 ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
661 }
662 }
663
664 void
665 ims332_set_curpos(sc)
666 struct xcfb_softc *sc;
667 {
668 struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
669 u_int32_t pos;
670
671 pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
672 ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
673 }
674
675 void
676 ims332_load_curcmap(sc)
677 struct xcfb_softc *sc;
678 {
679 u_int8_t *cp = sc->sc_cursor.cc_color;
680 u_int32_t rgb;
681
682 /* cursor background */
683 rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
684 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
685
686 /* cursor foreground */
687 rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
688 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
689 }
690
691 void
692 ims332_load_curshape(sc)
693 struct xcfb_softc *sc;
694 {
695 unsigned i, img, msk, bits;
696 u_int8_t u, *ip, *mp;
697
698 ip = (u_int8_t *)sc->sc_cursor.cc_image;
699 mp = (u_int8_t *)(sc->sc_cursor.cc_image+CURSOR_MAX_SIZE);
700
701 i = 0;
702 /* 64 pixel scan line is consisted with 8 halfward cursor ram */
703 while (i < sc->sc_cursor.cc_size.y * 8) {
704 /* pad right half 32 pixel when smaller than 33 */
705 if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
706 bits = 0;
707 else {
708 img = *ip++;
709 msk = *mp++;
710 img &= msk; /* cookie off image */
711 u = (msk & 0x0f) << 4 | (img & 0x0f);
712 bits = shuffle[u];
713 u = (msk & 0xf0) | (img & 0xf0) >> 4;
714 bits = (shuffle[u] << 8) | bits;
715 }
716 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
717 i += 1;
718 }
719 /* pad unoccupied scan lines */
720 while (i < CURSOR_MAX_SIZE * 8) {
721 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
722 i += 1;
723 }
724 }
725
726 u_int32_t
727 ims332_read_reg(regno)
728 int regno;
729 {
730 caddr_t imsreg = (caddr_t)IMS332_ADDRESS;
731 caddr_t rptr = (caddr_t)IMS332_RPTR + (regno << 4);
732 u_int v0, v1;
733
734 v1 = *(volatile u_int32_t *)imsreg;
735 v0 = *(volatile u_int16_t *)rptr;
736 return (v1 & 0xff00) << 8 | v0;
737 }
738
739 void
740 ims332_write_reg(regno, val)
741 int regno;
742 u_int32_t val;
743 {
744 caddr_t imsreg = (caddr_t)IMS332_ADDRESS;
745 caddr_t wptr = (caddr_t)IMS332_WPTR + (regno << 4);
746
747 *(volatile u_int32_t *)imsreg = (val & 0xff0000) >> 8;
748 *(volatile u_int16_t *)wptr = val;
749 }
750