sfb.c revision 1.8 1 /* $NetBSD: sfb.c,v 1.8 1999/01/15 23:31:25 thorpej 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: sfb.c,v 1.8 1999/01/15 23:31:25 thorpej 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/bt459reg.h>
57 #include <dev/tc/sfbreg.h>
58
59 #include "opt_uvm.h"
60 #if defined(UVM)
61 #include <uvm/uvm_extern.h>
62 #define useracc uvm_useracc
63 #endif
64
65 /* XXX BUS'IFYING XXX */
66
67 #if defined(pmax)
68 #define machine_btop(x) mips_btop(x)
69 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x)
70 #endif
71
72 #if defined(__alpha__) || defined(alpha)
73 #define machine_btop(x) alpha_btop(x)
74 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
75 #endif
76
77 /*
78 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have
79 * obscure register layout such as 2nd and 3rd Bt459 registers are
80 * adjacent each other in a word, i.e.,
81 * struct bt459triplet {
82 * struct {
83 * u_int8_t u0;
84 * u_int8_t u1;
85 * u_int8_t u2;
86 * unsigned :8;
87 * } bt_lo;
88 * ...
89 * Although HX has single Bt459, 32bit R/W can be done w/o any trouble.
90 */
91 struct bt459reg {
92 u_int32_t bt_lo;
93 u_int32_t bt_hi;
94 u_int32_t bt_reg;
95 u_int32_t bt_cmap;
96 };
97
98 /* XXX XXX XXX */
99
100 struct fb_devconfig {
101 vaddr_t dc_vaddr; /* memory space virtual base address */
102 paddr_t dc_paddr; /* memory space physical base address */
103 vsize_t dc_size; /* size of slot memory */
104 int dc_wid; /* width of frame buffer */
105 int dc_ht; /* height of frame buffer */
106 int dc_depth; /* depth, bits per pixel */
107 int dc_rowbytes; /* bytes in a FB scan line */
108 vaddr_t dc_videobase; /* base of flat frame buffer */
109 struct raster dc_raster; /* raster description */
110 struct rcons dc_rcons; /* raster blitter control info */
111 int dc_blanked; /* currently has video disabled */
112 };
113
114 struct hwcmap {
115 #define CMAP_SIZE 256 /* 256 R/G/B entries */
116 u_int8_t r[CMAP_SIZE];
117 u_int8_t g[CMAP_SIZE];
118 u_int8_t b[CMAP_SIZE];
119 };
120
121 struct hwcursor {
122 struct wsdisplay_curpos cc_pos;
123 struct wsdisplay_curpos cc_hot;
124 struct wsdisplay_curpos cc_size;
125 #define CURSOR_MAX_SIZE 64
126 u_int8_t cc_color[6];
127 u_int64_t cc_image[64 + 64];
128 };
129
130 struct sfb_softc {
131 struct device sc_dev;
132 struct fb_devconfig *sc_dc; /* device configuration */
133 struct hwcmap sc_cmap; /* software copy of colormap */
134 struct hwcursor sc_cursor; /* software copy of cursor */
135 int sc_curenb; /* cursor sprite enabled */
136 int sc_changed; /* need update of colormap */
137 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */
138 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */
139 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */
140 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */
141 #define DATA_ALL_CHANGED 0x0f
142 int nscreens;
143 short magic_x, magic_y; /* HX cursor location offset */
144 #define HX_MAGIC_X 368
145 #define HX_MAGIC_Y 38
146 };
147
148 int sfbmatch __P((struct device *, struct cfdata *, void *));
149 void sfbattach __P((struct device *, struct device *, void *));
150
151 struct cfattach sfb_ca = {
152 sizeof(struct sfb_softc), sfbmatch, sfbattach,
153 };
154
155 void sfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
156 struct fb_devconfig sfb_console_dc;
157 tc_addr_t sfb_consaddr;
158
159 struct wsdisplay_emulops sfb_emulops = {
160 rcons_cursor, /* could use hardware cursor; punt */
161 rcons_mapchar,
162 rcons_putchar,
163 rcons_copycols,
164 rcons_erasecols,
165 rcons_copyrows,
166 rcons_eraserows,
167 rcons_alloc_attr
168 };
169
170 struct wsscreen_descr sfb_stdscreen = {
171 "std", 0, 0,
172 &sfb_emulops,
173 0, 0,
174 0
175 };
176
177 const struct wsscreen_descr *_sfb_scrlist[] = {
178 &sfb_stdscreen,
179 };
180
181 struct wsscreen_list sfb_screenlist = {
182 sizeof(_sfb_scrlist) / sizeof(struct wsscreen_descr *), _sfb_scrlist
183 };
184
185 int sfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
186 int sfbmmap __P((void *, off_t, int));
187
188 int sfb_alloc_screen __P((void *, const struct wsscreen_descr *,
189 void **, int *, int *, long *));
190 void sfb_free_screen __P((void *, void *));
191 void sfb_show_screen __P((void *, void *));
192
193 struct wsdisplay_accessops sfb_accessops = {
194 sfbioctl,
195 sfbmmap,
196 sfb_alloc_screen,
197 sfb_free_screen,
198 sfb_show_screen,
199 0 /* load_font */
200 };
201
202 int sfb_cnattach __P((tc_addr_t));
203 int sfbintr __P((void *));
204 void sfbinit __P((struct fb_devconfig *));
205
206 static int get_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
207 static int set_cmap __P((struct sfb_softc *, struct wsdisplay_cmap *));
208 static int set_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
209 static int get_cursor __P((struct sfb_softc *, struct wsdisplay_cursor *));
210 static void set_curpos __P((struct sfb_softc *, struct wsdisplay_curpos *));
211 static void bt459_set_curpos __P((struct sfb_softc *));
212
213 /* XXX XXX XXX */
214 #define BT459_SELECT(vdac, regno) do { \
215 vdac->bt_lo = (regno) & 0x00ff; \
216 vdac->bt_hi = ((regno)& 0x0f00) >> 8 ; \
217 tc_wmb(); \
218 } while (0)
219 /* XXX XXX XXX */
220
221 /*
222 * Compose 2 bit/pixel cursor image. Bit order will be reversed.
223 * M M M M I I I I M I M I M I M I
224 * [ before ] [ after ]
225 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3
226 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7
227 */
228 const static u_int8_t shuffle[256] = {
229 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
230 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
231 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
232 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
233 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
234 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
235 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
236 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
237 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
238 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
239 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
240 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
241 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
242 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
243 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
244 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
245 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
246 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
247 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
248 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
249 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
250 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
251 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
252 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
253 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
254 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
255 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
256 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
257 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
258 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
259 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
260 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
261 };
262
263 int
264 sfbmatch(parent, match, aux)
265 struct device *parent;
266 struct cfdata *match;
267 void *aux;
268 {
269 struct tc_attach_args *ta = aux;
270
271 if (strncmp("PMAGB-BA", ta->ta_modname, TC_ROM_LLEN) != 0)
272 return (0);
273
274 return (1);
275 }
276
277 void
278 sfb_getdevconfig(dense_addr, dc)
279 tc_addr_t dense_addr;
280 struct fb_devconfig *dc;
281 {
282 struct raster *rap;
283 struct rcons *rcp;
284 caddr_t sfbasic;
285 int i, hsetup, vsetup, vbase;
286
287 dc->dc_vaddr = dense_addr;
288 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
289
290 sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
291 hsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_HSETUP);
292 vsetup = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VSETUP);
293 vbase = *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_BASE) & 0x1ff;
294
295 dc->dc_wid = (hsetup & 0x1ff) << 2;
296 dc->dc_ht = (vsetup & 0x7ff);
297 dc->dc_depth = 8;
298 dc->dc_rowbytes = dc->dc_wid * (dc->dc_depth / 8);
299 dc->dc_videobase = dc->dc_vaddr + SFB_FB_OFFSET + vbase * 4096;
300 dc->dc_blanked = 0;
301
302 /* initialize colormap and cursor resource */
303 sfbinit(dc);
304
305 /* clear the screen */
306 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
307 *(u_int32_t *)(dc->dc_videobase + i) = 0x0;
308
309 /* initialize the raster */
310 rap = &dc->dc_raster;
311 rap->width = dc->dc_wid;
312 rap->height = dc->dc_ht;
313 rap->depth = dc->dc_depth;
314 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
315 rap->pixels = (u_int32_t *)dc->dc_videobase;
316
317 /* initialize the raster console blitter */
318 rcp = &dc->dc_rcons;
319 rcp->rc_sp = rap;
320 rcp->rc_crow = rcp->rc_ccol = -1;
321 rcp->rc_crowp = &rcp->rc_crow;
322 rcp->rc_ccolp = &rcp->rc_ccol;
323 rcons_init(rcp, 34, 80);
324
325 sfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
326 sfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
327
328 }
329
330 void
331 sfbattach(parent, self, aux)
332 struct device *parent, *self;
333 void *aux;
334 {
335 struct sfb_softc *sc = (struct sfb_softc *)self;
336 struct tc_attach_args *ta = aux;
337 struct wsemuldisplaydev_attach_args waa;
338 struct hwcmap *cm;
339 caddr_t sfbasic;
340 int console, i;
341
342 console = (ta->ta_addr == sfb_consaddr);
343 if (console) {
344 sc->sc_dc = &sfb_console_dc;
345 sc->nscreens = 1;
346 }
347 else {
348 sc->sc_dc = (struct fb_devconfig *)
349 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
350 sfb_getdevconfig(ta->ta_addr, sc->sc_dc);
351 }
352 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
353 sc->sc_dc->dc_depth);
354
355 cm = &sc->sc_cmap;
356 cm->r[0] = cm->g[0] = cm->b[0] = 0;
357 for (i = 1; i < CMAP_SIZE; i++) {
358 cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
359 }
360 sc->magic_x = HX_MAGIC_X; sc->magic_y = HX_MAGIC_Y;
361
362 tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, sfbintr, sc);
363
364 sfbasic = (caddr_t)(sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET);
365 *(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
366 *(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1;
367
368 waa.console = console;
369 waa.scrdata = &sfb_screenlist;
370 waa.accessops = &sfb_accessops;
371 waa.accesscookie = sc;
372
373 config_found(self, &waa, wsemuldisplaydevprint);
374 }
375
376 int
377 sfbioctl(v, cmd, data, flag, p)
378 void *v;
379 u_long cmd;
380 caddr_t data;
381 int flag;
382 struct proc *p;
383 {
384 struct sfb_softc *sc = v;
385 struct fb_devconfig *dc = sc->sc_dc;
386 int turnoff;
387
388 switch (cmd) {
389 case WSDISPLAYIO_GTYPE:
390 *(u_int *)data = WSDISPLAY_TYPE_SFB;
391 return (0);
392
393 case WSDISPLAYIO_GINFO:
394 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
395 wsd_fbip->height = sc->sc_dc->dc_ht;
396 wsd_fbip->width = sc->sc_dc->dc_wid;
397 wsd_fbip->depth = sc->sc_dc->dc_depth;
398 wsd_fbip->cmsize = CMAP_SIZE;
399 #undef fbt
400 return (0);
401
402 case WSDISPLAYIO_GETCMAP:
403 return get_cmap(sc, (struct wsdisplay_cmap *)data);
404
405 case WSDISPLAYIO_PUTCMAP:
406 return set_cmap(sc, (struct wsdisplay_cmap *)data);
407
408 case WSDISPLAYIO_SVIDEO:
409 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
410 if ((dc->dc_blanked == 0) ^ turnoff) {
411 dc->dc_blanked = turnoff;
412 /* XXX later XXX */
413 }
414 return (0);
415
416 case WSDISPLAYIO_GVIDEO:
417 *(u_int *)data = dc->dc_blanked ?
418 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
419 return (0);
420
421 case WSDISPLAYIO_GCURPOS:
422 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
423 return (0);
424
425 case WSDISPLAYIO_SCURPOS:
426 set_curpos(sc, (struct wsdisplay_curpos *)data);
427 bt459_set_curpos(sc);
428 return (0);
429
430 case WSDISPLAYIO_GCURMAX:
431 ((struct wsdisplay_curpos *)data)->x =
432 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
433 return (0);
434
435 case WSDISPLAYIO_GCURSOR:
436 return get_cursor(sc, (struct wsdisplay_cursor *)data);
437
438 case WSDISPLAYIO_SCURSOR:
439 return set_cursor(sc, (struct wsdisplay_cursor *)data);
440 }
441 return ENOTTY;
442 }
443
444 int
445 sfbmmap(v, offset, prot)
446 void *v;
447 off_t offset;
448 int prot;
449 {
450 struct sfb_softc *sc = v;
451
452 if (offset >= 0x1000000 || offset < 0)
453 return (-1);
454 return machine_btop(sc->sc_dc->dc_paddr + offset);
455 }
456
457 int
458 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
459 void *v;
460 const struct wsscreen_descr *type;
461 void **cookiep;
462 int *curxp, *curyp;
463 long *attrp;
464 {
465 struct sfb_softc *sc = v;
466 long defattr;
467
468 if (sc->nscreens > 0)
469 return (ENOMEM);
470
471 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
472 *curxp = 0;
473 *curyp = 0;
474 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
475 *attrp = defattr;
476 sc->nscreens++;
477 return (0);
478 }
479
480 void
481 sfb_free_screen(v, cookie)
482 void *v;
483 void *cookie;
484 {
485 struct sfb_softc *sc = v;
486
487 if (sc->sc_dc == &sfb_console_dc)
488 panic("sfb_free_screen: console");
489
490 sc->nscreens--;
491 }
492
493 void
494 sfb_show_screen(v, cookie)
495 void *v;
496 void *cookie;
497 {
498 }
499
500 int
501 sfb_cnattach(addr)
502 tc_addr_t addr;
503 {
504 struct fb_devconfig *dcp = &sfb_console_dc;
505 long defattr;
506
507 sfb_getdevconfig(addr, dcp);
508
509 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
510
511 wsdisplay_cnattach(&sfb_stdscreen, &dcp->dc_rcons,
512 0, 0, defattr);
513 sfb_consaddr = addr;
514 return(0);
515 }
516
517 int
518 sfbintr(arg)
519 void *arg;
520 {
521 struct sfb_softc *sc = arg;
522 caddr_t sfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
523 caddr_t sfbasic = sfbbase + SFB_ASIC_OFFSET;
524 struct bt459reg *vdac;
525 int v;
526
527 *(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
528 /* *(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1; */
529
530 if (sc->sc_changed == 0)
531 return (1);
532
533 vdac = (void *)(sfbbase + SFB_RAMDAC_OFFSET);
534 v = sc->sc_changed;
535 sc->sc_changed = 0;
536
537 if (v & DATA_ENB_CHANGED) {
538 BT459_SELECT(vdac, BT459_REG_CCR);
539 vdac->bt_reg = (sc->sc_curenb) ? 0xc0 : 0x00;
540 }
541 if (v & DATA_CURCMAP_CHANGED) {
542 u_int8_t *cp = sc->sc_cursor.cc_color;
543
544 BT459_SELECT(vdac, BT459_REG_CCOLOR_2);
545 vdac->bt_reg = cp[1]; tc_wmb();
546 vdac->bt_reg = cp[3]; tc_wmb();
547 vdac->bt_reg = cp[5]; tc_wmb();
548
549 vdac->bt_reg = cp[0]; tc_wmb();
550 vdac->bt_reg = cp[2]; tc_wmb();
551 vdac->bt_reg = cp[4]; tc_wmb();
552 }
553 if (v & DATA_CURSHAPE_CHANGED) {
554 u_int8_t *ip, *mp, img, msk;
555 u_int8_t u;
556 int bcnt;
557
558 ip = (u_int8_t *)sc->sc_cursor.cc_image;
559 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
560
561 bcnt = 0;
562 BT459_SELECT(vdac, BT459_REG_CRAM_BASE+0);
563 /* 64 pixel scan line is consisted with 16 byte cursor ram */
564 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
565 /* pad right half 32 pixel when smaller than 33 */
566 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
567 vdac->bt_reg = 0; tc_wmb();
568 vdac->bt_reg = 0; tc_wmb();
569 }
570 else {
571 img = *ip++;
572 msk = *mp++;
573 img &= msk; /* cookie off image */
574 u = (msk & 0x0f) << 4 | (img & 0x0f);
575 vdac->bt_reg = shuffle[u]; tc_wmb();
576 u = (msk & 0xf0) | (img & 0xf0) >> 4;
577 vdac->bt_reg = shuffle[u]; tc_wmb();
578 }
579 bcnt += 2;
580 }
581 /* pad unoccupied scan lines */
582 while (bcnt < CURSOR_MAX_SIZE * 16) {
583 vdac->bt_reg = 0; tc_wmb();
584 vdac->bt_reg = 0; tc_wmb();
585 bcnt += 2;
586 }
587 }
588 if (v & DATA_CMAP_CHANGED) {
589 struct hwcmap *cm = &sc->sc_cmap;
590 int index;
591
592 BT459_SELECT(vdac, 0);
593 for (index = 0; index < CMAP_SIZE; index++) {
594 vdac->bt_cmap = cm->r[index]; tc_wmb();
595 vdac->bt_cmap = cm->g[index]; tc_wmb();
596 vdac->bt_cmap = cm->b[index]; tc_wmb();
597 }
598 }
599 return (1);
600 }
601
602 void
603 sfbinit(dc)
604 struct fb_devconfig *dc;
605 {
606 caddr_t sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
607 struct bt459reg *vdac = (void *)(dc->dc_vaddr + SFB_RAMDAC_OFFSET);
608 int i;
609
610 *(u_int32_t *)(sfbasic + SFB_ASIC_MODE) = 0;
611 *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VALID) = 1;
612 *(u_int32_t *)(sfbasic + SFB_ASIC_PLANEMASK) = ~0;
613 *(u_int32_t *)(sfbasic + SFB_ASIC_PIXELMASK) = ~0;
614
615 *(u_int32_t *)(sfbasic + 0x180000) = 0; /* Bt459 reset */
616
617 BT459_SELECT(vdac, BT459_REG_COMMAND_0);
618 vdac->bt_reg = 0x40; /* CMD0 */ tc_wmb();
619 vdac->bt_reg = 0x0; /* CMD1 */ tc_wmb();
620 vdac->bt_reg = 0xc0; /* CMD2 */ tc_wmb();
621 vdac->bt_reg = 0xff; /* PRM */ tc_wmb();
622 vdac->bt_reg = 0; /* 205 */ tc_wmb();
623 vdac->bt_reg = 0x0; /* PBM */ tc_wmb();
624 vdac->bt_reg = 0; /* 207 */ tc_wmb();
625 vdac->bt_reg = 0x0; /* ORM */ tc_wmb();
626 vdac->bt_reg = 0x0; /* OBM */ tc_wmb();
627 vdac->bt_reg = 0x0; /* ILV */ tc_wmb();
628 vdac->bt_reg = 0x0; /* TEST */ tc_wmb();
629
630 BT459_SELECT(vdac, BT459_REG_CCR);
631 vdac->bt_reg = 0x0; tc_wmb();
632 vdac->bt_reg = 0x0; tc_wmb();
633 vdac->bt_reg = 0x0; tc_wmb();
634 vdac->bt_reg = 0x0; tc_wmb();
635 vdac->bt_reg = 0x0; tc_wmb();
636 vdac->bt_reg = 0x0; tc_wmb();
637 vdac->bt_reg = 0x0; tc_wmb();
638 vdac->bt_reg = 0x0; tc_wmb();
639 vdac->bt_reg = 0x0; tc_wmb();
640 vdac->bt_reg = 0x0; tc_wmb();
641 vdac->bt_reg = 0x0; tc_wmb();
642 vdac->bt_reg = 0x0; tc_wmb();
643 vdac->bt_reg = 0x0; tc_wmb();
644
645 /* build sane colormap */
646 BT459_SELECT(vdac, 0);
647 vdac->bt_cmap = 0; tc_wmb();
648 vdac->bt_cmap = 0; tc_wmb();
649 vdac->bt_cmap = 0; tc_wmb();
650 for (i = 1; i < CMAP_SIZE; i++) {
651 vdac->bt_cmap = 0xff; tc_wmb();
652 vdac->bt_cmap = 0xff; tc_wmb();
653 vdac->bt_cmap = 0xff; tc_wmb();
654 }
655
656 /* clear out cursor image */
657 BT459_SELECT(vdac, BT459_REG_CRAM_BASE);
658 for (i = 0; i < 1024; i++)
659 vdac->bt_reg = 0xff; tc_wmb();
660
661 /*
662 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
663 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for
664 * image color. CCOLOR_1 will be never used.
665 */
666 BT459_SELECT(vdac, BT459_REG_CCOLOR_1);
667 vdac->bt_reg = 0xff; tc_wmb();
668 vdac->bt_reg = 0xff; tc_wmb();
669 vdac->bt_reg = 0xff; tc_wmb();
670
671 vdac->bt_reg = 0; tc_wmb();
672 vdac->bt_reg = 0; tc_wmb();
673 vdac->bt_reg = 0; tc_wmb();
674
675 vdac->bt_reg = 0xff; tc_wmb();
676 vdac->bt_reg = 0xff; tc_wmb();
677 vdac->bt_reg = 0xff; tc_wmb();
678 }
679
680 static int
681 get_cmap(sc, p)
682 struct sfb_softc *sc;
683 struct wsdisplay_cmap *p;
684 {
685 u_int index = p->index, count = p->count;
686
687 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
688 return (EINVAL);
689
690 if (!useracc(p->red, count, B_WRITE) ||
691 !useracc(p->green, count, B_WRITE) ||
692 !useracc(p->blue, count, B_WRITE))
693 return (EFAULT);
694
695 copyout(&sc->sc_cmap.r[index], p->red, count);
696 copyout(&sc->sc_cmap.g[index], p->green, count);
697 copyout(&sc->sc_cmap.b[index], p->blue, count);
698
699 return (0);
700 }
701
702 static int
703 set_cmap(sc, p)
704 struct sfb_softc *sc;
705 struct wsdisplay_cmap *p;
706 {
707 u_int index = p->index, count = p->count;
708
709 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
710 return (EINVAL);
711
712 if (!useracc(p->red, count, B_READ) ||
713 !useracc(p->green, count, B_READ) ||
714 !useracc(p->blue, count, B_READ))
715 return (EFAULT);
716
717 copyin(p->red, &sc->sc_cmap.r[index], count);
718 copyin(p->green, &sc->sc_cmap.g[index], count);
719 copyin(p->blue, &sc->sc_cmap.b[index], count);
720
721 sc->sc_changed |= DATA_CMAP_CHANGED;
722
723 return (0);
724 }
725
726
727 static int
728 set_cursor(sc, p)
729 struct sfb_softc *sc;
730 struct wsdisplay_cursor *p;
731 {
732 #define cc (&sc->sc_cursor)
733 int v, index, count, icount;
734
735 v = p->which;
736 if (v & WSDISPLAY_CURSOR_DOCMAP) {
737 index = p->cmap.index;
738 count = p->cmap.count;
739 if (index >= 2 || (index + count) > 2)
740 return (EINVAL);
741 if (!useracc(p->cmap.red, count, B_READ) ||
742 !useracc(p->cmap.green, count, B_READ) ||
743 !useracc(p->cmap.blue, count, B_READ))
744 return (EFAULT);
745 }
746 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
747 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
748 return (EINVAL);
749 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
750 if (!useracc(p->image, count, B_READ) ||
751 !useracc(p->mask, count, B_READ))
752 return (EFAULT);
753 }
754 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
755 if (v & WSDISPLAY_CURSOR_DOCUR)
756 cc->cc_hot = p->hot;
757 if (v & WSDISPLAY_CURSOR_DOPOS)
758 set_curpos(sc, &p->pos);
759 bt459_set_curpos(sc);
760 }
761
762 sc->sc_changed = 0;
763 if (v & WSDISPLAY_CURSOR_DOCUR) {
764 sc->sc_curenb = p->enable;
765 sc->sc_changed |= DATA_ENB_CHANGED;
766 }
767 if (v & WSDISPLAY_CURSOR_DOCMAP) {
768 copyin(p->cmap.red, &cc->cc_color[index], count);
769 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
770 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
771 sc->sc_changed |= DATA_CURCMAP_CHANGED;
772 }
773 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
774 cc->cc_size = p->size;
775 memset(cc->cc_image, 0, sizeof cc->cc_image);
776 copyin(p->image, cc->cc_image, icount);
777 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
778 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
779 }
780
781 return (0);
782 #undef cc
783 }
784
785 static int
786 get_cursor(sc, p)
787 struct sfb_softc *sc;
788 struct wsdisplay_cursor *p;
789 {
790 return (ENOTTY); /* XXX */
791 }
792
793 static void
794 set_curpos(sc, curpos)
795 struct sfb_softc *sc;
796 struct wsdisplay_curpos *curpos;
797 {
798 struct fb_devconfig *dc = sc->sc_dc;
799 int x = curpos->x, y = curpos->y;
800
801 if (y < 0)
802 y = 0;
803 else if (y > dc->dc_ht)
804 y = dc->dc_ht;
805 if (x < 0)
806 x = 0;
807 else if (x > dc->dc_wid)
808 x = dc->dc_wid;
809 sc->sc_cursor.cc_pos.x = x;
810 sc->sc_cursor.cc_pos.y = y;
811 }
812
813 static void
814 bt459_set_curpos(sc)
815 struct sfb_softc *sc;
816 {
817 caddr_t sfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
818 struct bt459reg *vdac = (void *)(sfbbase + SFB_RAMDAC_OFFSET);
819 int x, y, s;
820
821 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
822 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
823 x += sc->magic_x; y += sc->magic_y; /* magic offset of HX coordinate */
824
825 s = spltty();
826
827 BT459_SELECT(vdac, BT459_REG_CURSOR_X_LOW);
828 vdac->bt_reg = x; tc_wmb();
829 vdac->bt_reg = x >> 8; tc_wmb();
830 vdac->bt_reg = y; tc_wmb();
831 vdac->bt_reg = y >> 8; tc_wmb();
832
833 splx(s);
834 }
835