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