xcfb.c revision 1.10 1 /* $NetBSD: xcfb.c,v 1.10 1999/04/30 09:43:23 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.10 1999/04/30 09:43:23 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 struct hwcmap *cm;
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 cm = &sc->sc_cmap;
311 memset(cm, 255, sizeof(struct hwcmap)); /* XXX */
312 cm->r[0] = cm->g[0] = cm->b[0] = 0; /* XXX */
313
314 sc->sc_csr = IMS332_BPP_8 | IMS332_CSR_A_VTG_ENABLE;
315
316 tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, xcfbintr, sc);
317
318 waa.console = console;
319 waa.scrdata = &xcfb_screenlist;
320 waa.accessops = &xcfb_accessops;
321 waa.accesscookie = sc;
322
323 config_found(self, &waa, wsemuldisplaydevprint);
324 }
325
326 int
327 xcfbioctl(v, cmd, data, flag, p)
328 void *v;
329 u_long cmd;
330 caddr_t data;
331 int flag;
332 struct proc *p;
333 {
334 struct xcfb_softc *sc = v;
335 struct fb_devconfig *dc = sc->sc_dc;
336 int turnoff, error;
337
338 switch (cmd) {
339 case WSDISPLAYIO_GTYPE:
340 *(u_int *)data = WSDISPLAY_TYPE_XCFB;
341 return (0);
342
343 case WSDISPLAYIO_GINFO:
344 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
345 wsd_fbip->height = sc->sc_dc->dc_ht;
346 wsd_fbip->width = sc->sc_dc->dc_wid;
347 wsd_fbip->depth = sc->sc_dc->dc_depth;
348 wsd_fbip->cmsize = CMAP_SIZE;
349 #undef fbt
350 return (0);
351
352 case WSDISPLAYIO_GETCMAP:
353 return get_cmap(sc, (struct wsdisplay_cmap *)data);
354
355 case WSDISPLAYIO_PUTCMAP:
356 error = set_cmap(sc, (struct wsdisplay_cmap *)data);
357 if (error == 0)
358 ims332_loadcmap(&sc->sc_cmap);
359 return (error);
360
361 case WSDISPLAYIO_SVIDEO:
362 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
363 if ((dc->dc_blanked == 0) ^ turnoff) {
364 dc->dc_blanked = turnoff;
365 xcfb_screenblank(sc);
366 }
367 return (0);
368
369 case WSDISPLAYIO_GVIDEO:
370 *(u_int *)data = dc->dc_blanked ?
371 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
372 return (0);
373
374 case WSDISPLAYIO_GCURPOS:
375 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
376 return (0);
377
378 case WSDISPLAYIO_SCURPOS:
379 set_curpos(sc, (struct wsdisplay_curpos *)data);
380 ims332_set_curpos(sc);
381 return (0);
382
383 case WSDISPLAYIO_GCURMAX:
384 ((struct wsdisplay_curpos *)data)->x =
385 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
386 return (0);
387
388 case WSDISPLAYIO_GCURSOR:
389 return get_cursor(sc, (struct wsdisplay_cursor *)data);
390
391 case WSDISPLAYIO_SCURSOR:
392 return set_cursor(sc, (struct wsdisplay_cursor *)data);
393 }
394 return ENOTTY;
395 }
396
397 int
398 xcfbmmap(v, offset, prot)
399 void *v;
400 off_t offset;
401 int prot;
402 {
403 struct xcfb_softc *sc = v;
404
405 if (offset >= XCFB_FB_SIZE || offset < 0)
406 return -1;
407 return mips_btop(sc->sc_dc->dc_paddr + offset);
408 }
409
410 int
411 xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
412 void *v;
413 const struct wsscreen_descr *type;
414 void **cookiep;
415 int *curxp, *curyp;
416 long *attrp;
417 {
418 struct xcfb_softc *sc = v;
419 long defattr;
420
421 if (sc->nscreens > 0)
422 return (ENOMEM);
423
424 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
425 *curxp = 0;
426 *curyp = 0;
427 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
428 *attrp = defattr;
429 sc->nscreens++;
430 return (0);
431 }
432
433 void
434 xcfb_free_screen(v, cookie)
435 void *v;
436 void *cookie;
437 {
438 struct xcfb_softc *sc = v;
439
440 if (sc->sc_dc == &xcfb_console_dc)
441 panic("xcfb_free_screen: console");
442
443 sc->nscreens--;
444 }
445
446 void
447 xcfb_show_screen(v, cookie)
448 void *v;
449 void *cookie;
450 {
451 }
452
453 int
454 xcfb_cnattach(addr)
455 tc_addr_t addr;
456 {
457 struct fb_devconfig *dcp = &xcfb_console_dc;
458 long defattr;
459
460 xcfb_getdevconfig(addr, dcp);
461
462 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
463
464 wsdisplay_cnattach(&xcfb_stdscreen, &dcp->dc_rcons,
465 0, 0, defattr);
466 xcfb_consaddr = addr;
467 return (0);
468 }
469
470 int
471 xcfbintr(v)
472 void *v;
473 {
474 int intr;
475
476 intr = *(u_int32_t *)(ioasic_base + IOASIC_INTR);
477 intr &= ~XINE_INTR_VINT;
478 *(u_int32_t *)(ioasic_base + IOASIC_INTR) = intr;
479 return 1;
480 }
481
482 void
483 xcfbinit(dc)
484 struct fb_devconfig *dc;
485 {
486 u_int32_t csr;
487 int i;
488
489 csr = *(u_int32_t *)(ioasic_base + IOASIC_CSR);
490 csr &= ~XINE_CSR_VDAC_ENABLE;
491 *(u_int32_t *)(ioasic_base + IOASIC_CSR) = csr;
492 DELAY(50);
493 csr |= XINE_CSR_VDAC_ENABLE;
494 *(u_int32_t *)(ioasic_base + IOASIC_CSR) = csr;
495 DELAY(50);
496 ims332_write_reg(IMS332_REG_BOOT, 0x2c);
497 ims332_write_reg(IMS332_REG_CSR_A,
498 IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
499 ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
500 ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
501 ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
502 ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
503 ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
504 ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
505 ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
506 ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
507 ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
508 ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
509 ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
510 ims332_write_reg(IMS332_REG_LINE_START, 0x10);
511 ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
512 ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
513 ims332_write_reg(IMS332_REG_CSR_A,
514 IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
515
516 /* build sane colormap */
517 ims332_write_reg(IMS332_REG_LUT_BASE, 0);
518 for (i = 1; i < CMAP_SIZE; i++)
519 ims332_write_reg(IMS332_REG_LUT_BASE + i, 0xffffff);
520
521 /* clear out cursor image */
522 for (i = 0; i < 512; i++)
523 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
524
525 /*
526 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
527 * cursor image. LUT_1 for mask color, while LUT_2 for
528 * image color. LUT_0 will be never used.
529 */
530 ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
531 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
532 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
533 }
534
535 void
536 xcfb_screenblank(sc)
537 struct xcfb_softc *sc;
538 {
539 if (sc->sc_dc->dc_blanked)
540 sc->sc_csr |= IMS332_CSR_A_FORCE_BLANK;
541 else
542 sc->sc_csr &= ~IMS332_CSR_A_FORCE_BLANK;
543 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
544 }
545
546 static int
547 get_cmap(sc, p)
548 struct xcfb_softc *sc;
549 struct wsdisplay_cmap *p;
550 {
551 u_int index = p->index, count = p->count;
552
553 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
554 return (EINVAL);
555
556 if (!uvm_useracc(p->red, count, B_WRITE) ||
557 !uvm_useracc(p->green, count, B_WRITE) ||
558 !uvm_useracc(p->blue, count, B_WRITE))
559 return (EFAULT);
560
561 copyout(&sc->sc_cmap.r[index], p->red, count);
562 copyout(&sc->sc_cmap.g[index], p->green, count);
563 copyout(&sc->sc_cmap.b[index], p->blue, count);
564
565 return (0);
566 }
567
568 static int
569 set_cmap(sc, p)
570 struct xcfb_softc *sc;
571 struct wsdisplay_cmap *p;
572 {
573 u_int index = p->index, count = p->count;
574
575 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
576 return (EINVAL);
577
578 if (!uvm_useracc(p->red, count, B_READ) ||
579 !uvm_useracc(p->green, count, B_READ) ||
580 !uvm_useracc(p->blue, count, B_READ))
581 return (EFAULT);
582
583 copyin(p->red, &sc->sc_cmap.r[index], count);
584 copyin(p->green, &sc->sc_cmap.g[index], count);
585 copyin(p->blue, &sc->sc_cmap.b[index], count);
586
587 return (0);
588 }
589
590 static int
591 set_cursor(sc, p)
592 struct xcfb_softc *sc;
593 struct wsdisplay_cursor *p;
594 {
595 #define cc (&sc->sc_cursor)
596 int v, index, count;
597
598 v = p->which;
599 if (v & WSDISPLAY_CURSOR_DOCMAP) {
600 index = p->cmap.index;
601 count = p->cmap.count;
602
603 if (index >= 2 || index + count > 2)
604 return (EINVAL);
605 if (!uvm_useracc(p->cmap.red, count, B_READ) ||
606 !uvm_useracc(p->cmap.green, count, B_READ) ||
607 !uvm_useracc(p->cmap.blue, count, B_READ))
608 return (EFAULT);
609
610 copyin(p->cmap.red, &cc->cc_color[index], count);
611 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
612 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
613 ims332_load_curcmap(sc);
614 }
615 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
616 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
617 return (EINVAL);
618 count = ((p->size.x < 33) ? 4 : 8) * p->size.y;
619 if (!uvm_useracc(p->image, count, B_READ) ||
620 !uvm_useracc(p->mask, count, B_READ))
621 return (EFAULT);
622 cc->cc_size = p->size;
623 memset(cc->cc_image, 0, sizeof cc->cc_image);
624 copyin(p->image, cc->cc_image, count);
625 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count);
626 ims332_load_curshape(sc);
627 }
628 if (v & WSDISPLAY_CURSOR_DOCUR) {
629 cc->cc_hot = p->hot;
630 if (p->enable)
631 sc->sc_csr &= ~IMS332_CSR_A_DISABLE_CURSOR;
632 else
633 sc->sc_csr |= IMS332_CSR_A_DISABLE_CURSOR;
634 ims332_write_reg(IMS332_REG_CSR_A, sc->sc_csr);
635 }
636 if (v & WSDISPLAY_CURSOR_DOPOS) {
637 set_curpos(sc, &p->pos);
638 ims332_set_curpos(sc);
639 }
640
641 return (0);
642 #undef cc
643 }
644
645 static int
646 get_cursor(sc, p)
647 struct xcfb_softc *sc;
648 struct wsdisplay_cursor *p;
649 {
650 return (ENOTTY); /* XXX */
651 }
652
653 static void
654 set_curpos(sc, curpos)
655 struct xcfb_softc *sc;
656 struct wsdisplay_curpos *curpos;
657 {
658 struct fb_devconfig *dc = sc->sc_dc;
659 int x = curpos->x, y = curpos->y;
660
661 if (y < 0)
662 y = 0;
663 else if (y > dc->dc_ht)
664 y = dc->dc_ht;
665 if (x < 0)
666 x = 0;
667 else if (x > dc->dc_wid)
668 x = dc->dc_wid;
669 sc->sc_cursor.cc_pos.x = x;
670 sc->sc_cursor.cc_pos.y = y;
671 }
672
673 void
674 ims332_loadcmap(cm)
675 struct hwcmap *cm;
676 {
677 int i;
678 u_int32_t rgb;
679
680 for (i = 0; i < CMAP_SIZE; i++) {
681 rgb = cm->b[i] << 16 | cm->g[i] << 8 | cm->r[i];
682 ims332_write_reg(IMS332_REG_LUT_BASE + i, rgb);
683 }
684 }
685
686 void
687 ims332_set_curpos(sc)
688 struct xcfb_softc *sc;
689 {
690 struct wsdisplay_curpos *curpos = &sc->sc_cursor.cc_pos;
691 u_int32_t pos;
692 int s;
693
694 s = spltty();
695 pos = (curpos->x & 0xfff) << 12 | (curpos->y & 0xfff);
696 ims332_write_reg(IMS332_REG_CURSOR_LOC, pos);
697 splx(s);
698 }
699
700 void
701 ims332_load_curcmap(sc)
702 struct xcfb_softc *sc;
703 {
704 u_int8_t *cp = sc->sc_cursor.cc_color;
705 u_int32_t rgb;
706
707 /* cursor background */
708 rgb = cp[5] << 16 | cp[3] << 8 | cp[1];
709 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, rgb);
710
711 /* cursor foreground */
712 rgb = cp[4] << 16 | cp[2] << 8 | cp[0];
713 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, rgb);
714 }
715
716 void
717 ims332_load_curshape(sc)
718 struct xcfb_softc *sc;
719 {
720 unsigned i, img, msk, bits;
721 u_int8_t u, *ip, *mp;
722
723 ip = (u_int8_t *)sc->sc_cursor.cc_image;
724 mp = (u_int8_t *)(sc->sc_cursor.cc_image+CURSOR_MAX_SIZE);
725
726 i = 0;
727 /* 64 pixel scan line is consisted with 8 halfward cursor ram */
728 while (i < sc->sc_cursor.cc_size.y * 8) {
729 /* pad right half 32 pixel when smaller than 33 */
730 if ((i & 0x4) && sc->sc_cursor.cc_size.x < 33)
731 bits = 0;
732 else {
733 img = *ip++;
734 msk = *mp++;
735 img &= msk; /* cookie off image */
736 u = (msk & 0x0f) << 4 | (img & 0x0f);
737 bits = shuffle[u];
738 u = (msk & 0xf0) | (img & 0xf0) >> 4;
739 bits = (shuffle[u] << 8) | bits;
740 }
741 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, bits);
742 i += 1;
743 }
744 /* pad unoccupied scan lines */
745 while (i < CURSOR_MAX_SIZE * 8) {
746 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
747 i += 1;
748 }
749 }
750
751 u_int32_t
752 ims332_read_reg(regno)
753 int regno;
754 {
755 caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
756 caddr_t low16 = (caddr_t)(ioasic_base + IMS332_RLOW) + (regno << 4);
757 u_int v0, v1;
758
759 v1 = *(volatile u_int16_t *)high8;
760 v0 = *(volatile u_int16_t *)low16;
761 return (v1 & 0xff00) << 8 | v0;
762 }
763
764 void
765 ims332_write_reg(regno, val)
766 int regno;
767 u_int32_t val;
768 {
769 caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
770 caddr_t low16 = (caddr_t)(ioasic_base + IMS332_WLOW) + (regno << 4);
771
772 *(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8;
773 *(volatile u_int16_t *)low16 = val;
774 }
775