xcfb.c revision 1.13 1 /* $NetBSD: xcfb.c,v 1.13 1999/11/29 07:50:55 nisimura 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.13 1999/11/29 07:50:55 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 #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 struct raster dc_raster; /* raster description */
71 struct rcons dc_rcons; /* raster blitter control info */
72 int dc_blanked; /* currently has video disabled */
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 virtical retrace interrupt XXX */
105 int nscreens;
106 /* cursor coordiate 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 static const struct wsdisplay_emulops xcfb_emulops = {
124 rcons_cursor,
125 rcons_mapchar,
126 rcons_putchar,
127 rcons_copycols,
128 rcons_erasecols,
129 rcons_copyrows,
130 rcons_eraserows,
131 rcons_alloc_attr
132 };
133
134 struct wsscreen_descr xcfb_stdscreen = {
135 "std",
136 0, 0, /* will be filled in -- XXX shouldn't, it's global */
137 &xcfb_emulops,
138 0, 0,
139 WSSCREEN_REVERSE
140 };
141
142 static const struct wsscreen_descr *_xcfb_scrlist[] = {
143 &xcfb_stdscreen,
144 };
145
146 static const struct wsscreen_list xcfb_screenlist = {
147 sizeof(_xcfb_scrlist) / sizeof(struct wsscreen_descr *), _xcfb_scrlist
148 };
149
150 static int xcfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
151 static int xcfbmmap __P((void *, off_t, int));
152
153 static int xcfb_alloc_screen __P((void *, const struct wsscreen_descr *,
154 void **, int *, int *, long *));
155 static void xcfb_free_screen __P((void *, void *));
156 static void xcfb_show_screen __P((void *, void *));
157
158 static const struct wsdisplay_accessops xcfb_accessops = {
159 xcfbioctl,
160 xcfbmmap,
161 xcfb_alloc_screen,
162 xcfb_free_screen,
163 xcfb_show_screen,
164 0 /* load_font */
165 };
166
167 static int xcfbintr __P((void *));
168 static void xcfb_screenblank __P((struct xcfb_softc *));
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 static void ims332_loadcmap __P((struct hwcmap256 *));
175 static void ims332_set_curpos __P((struct xcfb_softc *));
176 static void ims332_load_curcmap __P((struct xcfb_softc *));
177 static void ims332_load_curshape __P((struct xcfb_softc *));
178 static void ims332_write_reg __P((int, u_int32_t));
179 #if 0
180 static u_int32_t ims332_read_reg __P((int));
181 #endif
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 static const 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 static 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 static 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 static 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, 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 xcfb_cnattach()
329 {
330 tc_addr_t addr = MIPS_PHYS_TO_KSEG1(XINE_PHYS_CFB_START);
331 struct fb_devconfig *dcp = &xcfb_console_dc;
332 long defattr;
333
334 xcfb_getdevconfig(addr, dcp);
335
336 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
337
338 wsdisplay_cnattach(&xcfb_stdscreen, &dcp->dc_rcons,
339 0, 0, defattr);
340 xcfb_consaddr = addr;
341 return (0);
342 }
343
344 static void
345 xcfbinit(dc)
346 struct fb_devconfig *dc;
347 {
348 u_int32_t csr;
349 int i;
350
351 csr = *(u_int32_t *)(ioasic_base + IOASIC_CSR);
352 csr &= ~XINE_CSR_VDAC_ENABLE;
353 *(u_int32_t *)(ioasic_base + IOASIC_CSR) = csr;
354 DELAY(50);
355 csr |= XINE_CSR_VDAC_ENABLE;
356 *(u_int32_t *)(ioasic_base + IOASIC_CSR) = csr;
357 DELAY(50);
358 ims332_write_reg(IMS332_REG_BOOT, 0x2c);
359 ims332_write_reg(IMS332_REG_CSR_A,
360 IMS332_BPP_8|IMS332_CSR_A_DISABLE_CURSOR);
361 ims332_write_reg(IMS332_REG_HALF_SYNCH, 0x10);
362 ims332_write_reg(IMS332_REG_BACK_PORCH, 0x21);
363 ims332_write_reg(IMS332_REG_DISPLAY, 0x100);
364 ims332_write_reg(IMS332_REG_SHORT_DIS, 0x5d);
365 ims332_write_reg(IMS332_REG_BROAD_PULSE, 0x9f);
366 ims332_write_reg(IMS332_REG_LINE_TIME, 0x146);
367 ims332_write_reg(IMS332_REG_V_SYNC, 0x0c);
368 ims332_write_reg(IMS332_REG_V_PRE_EQUALIZE, 0x02);
369 ims332_write_reg(IMS332_REG_V_POST_EQUALIZE, 0x02);
370 ims332_write_reg(IMS332_REG_V_BLANK, 0x2a);
371 ims332_write_reg(IMS332_REG_V_DISPLAY, 0x600);
372 ims332_write_reg(IMS332_REG_LINE_START, 0x10);
373 ims332_write_reg(IMS332_REG_MEM_INIT, 0x0a);
374 ims332_write_reg(IMS332_REG_COLOR_MASK, 0xffffff);
375 ims332_write_reg(IMS332_REG_CSR_A,
376 IMS332_BPP_8|IMS332_CSR_A_VTG_ENABLE);
377
378 /* build sane colormap */
379 ims332_write_reg(IMS332_REG_LUT_BASE, 0);
380 for (i = 1; i < CMAP_SIZE; i++)
381 ims332_write_reg(IMS332_REG_LUT_BASE + i, 0xffffff);
382
383 /* clear out cursor image */
384 for (i = 0; i < 512; i++)
385 ims332_write_reg(IMS332_REG_CURSOR_RAM + i, 0);
386
387 /*
388 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
389 * cursor image. LUT_1 for mask color, while LUT_2 for
390 * image color. LUT_0 will be never used.
391 */
392 ims332_write_reg(IMS332_REG_CURSOR_LUT_0, 0);
393 ims332_write_reg(IMS332_REG_CURSOR_LUT_1, 0xffffff);
394 ims332_write_reg(IMS332_REG_CURSOR_LUT_2, 0xffffff);
395 }
396
397 static int
398 xcfbioctl(v, cmd, data, flag, p)
399 void *v;
400 u_long cmd;
401 caddr_t data;
402 int flag;
403 struct proc *p;
404 {
405 struct xcfb_softc *sc = v;
406 struct fb_devconfig *dc = sc->sc_dc;
407 int turnoff, error;
408
409 switch (cmd) {
410 case WSDISPLAYIO_GTYPE:
411 *(u_int *)data = WSDISPLAY_TYPE_XCFB;
412 return (0);
413
414 case WSDISPLAYIO_GINFO:
415 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
416 wsd_fbip->height = sc->sc_dc->dc_ht;
417 wsd_fbip->width = sc->sc_dc->dc_wid;
418 wsd_fbip->depth = sc->sc_dc->dc_depth;
419 wsd_fbip->cmsize = CMAP_SIZE;
420 #undef fbt
421 return (0);
422
423 case WSDISPLAYIO_GETCMAP:
424 return get_cmap(sc, (struct wsdisplay_cmap *)data);
425
426 case WSDISPLAYIO_PUTCMAP:
427 error = set_cmap(sc, (struct wsdisplay_cmap *)data);
428 if (error == 0)
429 ims332_loadcmap(&sc->sc_cmap);
430 return (error);
431
432 case WSDISPLAYIO_SVIDEO:
433 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
434 if ((dc->dc_blanked == 0) ^ turnoff) {
435 dc->dc_blanked = turnoff;
436 xcfb_screenblank(sc);
437 }
438 return (0);
439
440 case WSDISPLAYIO_GVIDEO:
441 *(u_int *)data = dc->dc_blanked ?
442 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
443 return (0);
444
445 case WSDISPLAYIO_GCURPOS:
446 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
447 return (0);
448
449 case WSDISPLAYIO_SCURPOS:
450 set_curpos(sc, (struct wsdisplay_curpos *)data);
451 ims332_set_curpos(sc);
452 return (0);
453
454 case WSDISPLAYIO_GCURMAX:
455 ((struct wsdisplay_curpos *)data)->x =
456 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
457 return (0);
458
459 case WSDISPLAYIO_GCURSOR:
460 return get_cursor(sc, (struct wsdisplay_cursor *)data);
461
462 case WSDISPLAYIO_SCURSOR:
463 return set_cursor(sc, (struct wsdisplay_cursor *)data);
464 }
465 return ENOTTY;
466 }
467
468 static int
469 xcfbmmap(v, offset, prot)
470 void *v;
471 off_t offset;
472 int prot;
473 {
474 struct xcfb_softc *sc = v;
475
476 if (offset >= XCFB_FB_SIZE || offset < 0)
477 return -1;
478 return mips_btop(sc->sc_dc->dc_paddr + offset);
479 }
480
481 static int
482 xcfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
483 void *v;
484 const struct wsscreen_descr *type;
485 void **cookiep;
486 int *curxp, *curyp;
487 long *attrp;
488 {
489 struct xcfb_softc *sc = v;
490 long defattr;
491
492 if (sc->nscreens > 0)
493 return (ENOMEM);
494
495 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
496 *curxp = 0;
497 *curyp = 0;
498 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
499 *attrp = defattr;
500 sc->nscreens++;
501 return (0);
502 }
503
504 static void
505 xcfb_free_screen(v, cookie)
506 void *v;
507 void *cookie;
508 {
509 struct xcfb_softc *sc = v;
510
511 if (sc->sc_dc == &xcfb_console_dc)
512 panic("xcfb_free_screen: console");
513
514 sc->nscreens--;
515 }
516
517 static void
518 xcfb_show_screen(v, cookie)
519 void *v;
520 void *cookie;
521 {
522 }
523
524 static int
525 xcfbintr(v)
526 void *v;
527 {
528 int intr;
529
530 intr = *(u_int32_t *)(ioasic_base + IOASIC_INTR);
531 intr &= ~XINE_INTR_VINT;
532 *(u_int32_t *)(ioasic_base + IOASIC_INTR) = intr;
533 return 1;
534 }
535
536 static 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 static 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 static 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 static 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 static 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 static void
753 ims332_write_reg(regno, val)
754 int regno;
755 u_int32_t val;
756 {
757 caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
758 caddr_t low16 = (caddr_t)(ioasic_base + IMS332_WLOW) + (regno << 4);
759
760 *(volatile u_int16_t *)high8 = (val & 0xff0000) >> 8;
761 *(volatile u_int16_t *)low16 = val;
762 }
763
764 #if 0
765 static u_int32_t
766 ims332_read_reg(regno)
767 int regno;
768 {
769 caddr_t high8 = (caddr_t)(ioasic_base + IMS332_HIGH);
770 caddr_t low16 = (caddr_t)(ioasic_base + IMS332_RLOW) + (regno << 4);
771 u_int v0, v1;
772
773 v1 = *(volatile u_int16_t *)high8;
774 v0 = *(volatile u_int16_t *)low16;
775 return (v1 & 0xff00) << 8 | v0;
776 }
777 #endif
778