sfb.c revision 1.9 1 /* $NetBSD: sfb.c,v 1.9 1999/02/19 03:42:42 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: sfb.c,v 1.9 1999/02/19 03:42:42 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 #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 *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VALID) = 1;
310
311 /* initialize the raster */
312 rap = &dc->dc_raster;
313 rap->width = dc->dc_wid;
314 rap->height = dc->dc_ht;
315 rap->depth = dc->dc_depth;
316 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
317 rap->pixels = (u_int32_t *)dc->dc_videobase;
318
319 /* initialize the raster console blitter */
320 rcp = &dc->dc_rcons;
321 rcp->rc_sp = rap;
322 rcp->rc_crow = rcp->rc_ccol = -1;
323 rcp->rc_crowp = &rcp->rc_crow;
324 rcp->rc_ccolp = &rcp->rc_ccol;
325 rcons_init(rcp, 34, 80);
326
327 sfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
328 sfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
329
330 }
331
332 void
333 sfbattach(parent, self, aux)
334 struct device *parent, *self;
335 void *aux;
336 {
337 struct sfb_softc *sc = (struct sfb_softc *)self;
338 struct tc_attach_args *ta = aux;
339 struct wsemuldisplaydev_attach_args waa;
340 struct hwcmap *cm;
341 caddr_t sfbasic;
342 int console, i;
343
344 console = (ta->ta_addr == sfb_consaddr);
345 if (console) {
346 sc->sc_dc = &sfb_console_dc;
347 sc->nscreens = 1;
348 }
349 else {
350 sc->sc_dc = (struct fb_devconfig *)
351 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
352 sfb_getdevconfig(ta->ta_addr, sc->sc_dc);
353 }
354 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
355 sc->sc_dc->dc_depth);
356
357 cm = &sc->sc_cmap;
358 cm->r[0] = cm->g[0] = cm->b[0] = 0;
359 for (i = 1; i < CMAP_SIZE; i++) {
360 cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
361 }
362 sc->magic_x = HX_MAGIC_X; sc->magic_y = HX_MAGIC_Y;
363
364 tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, sfbintr, sc);
365
366 sfbasic = (caddr_t)(sc->sc_dc->dc_vaddr + SFB_ASIC_OFFSET);
367 *(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
368 *(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1;
369
370 waa.console = console;
371 waa.scrdata = &sfb_screenlist;
372 waa.accessops = &sfb_accessops;
373 waa.accesscookie = sc;
374
375 config_found(self, &waa, wsemuldisplaydevprint);
376 }
377
378 int
379 sfbioctl(v, cmd, data, flag, p)
380 void *v;
381 u_long cmd;
382 caddr_t data;
383 int flag;
384 struct proc *p;
385 {
386 struct sfb_softc *sc = v;
387 struct fb_devconfig *dc = sc->sc_dc;
388 int turnoff;
389
390 switch (cmd) {
391 case WSDISPLAYIO_GTYPE:
392 *(u_int *)data = WSDISPLAY_TYPE_SFB;
393 return (0);
394
395 case WSDISPLAYIO_GINFO:
396 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
397 wsd_fbip->height = sc->sc_dc->dc_ht;
398 wsd_fbip->width = sc->sc_dc->dc_wid;
399 wsd_fbip->depth = sc->sc_dc->dc_depth;
400 wsd_fbip->cmsize = CMAP_SIZE;
401 #undef fbt
402 return (0);
403
404 case WSDISPLAYIO_GETCMAP:
405 return get_cmap(sc, (struct wsdisplay_cmap *)data);
406
407 case WSDISPLAYIO_PUTCMAP:
408 return set_cmap(sc, (struct wsdisplay_cmap *)data);
409
410 case WSDISPLAYIO_SVIDEO:
411 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
412 if ((dc->dc_blanked == 0) ^ turnoff) {
413 dc->dc_blanked = turnoff;
414 /* XXX later XXX */
415 }
416 return (0);
417
418 case WSDISPLAYIO_GVIDEO:
419 *(u_int *)data = dc->dc_blanked ?
420 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
421 return (0);
422
423 case WSDISPLAYIO_GCURPOS:
424 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
425 return (0);
426
427 case WSDISPLAYIO_SCURPOS:
428 set_curpos(sc, (struct wsdisplay_curpos *)data);
429 bt459_set_curpos(sc);
430 return (0);
431
432 case WSDISPLAYIO_GCURMAX:
433 ((struct wsdisplay_curpos *)data)->x =
434 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
435 return (0);
436
437 case WSDISPLAYIO_GCURSOR:
438 return get_cursor(sc, (struct wsdisplay_cursor *)data);
439
440 case WSDISPLAYIO_SCURSOR:
441 return set_cursor(sc, (struct wsdisplay_cursor *)data);
442 }
443 return ENOTTY;
444 }
445
446 int
447 sfbmmap(v, offset, prot)
448 void *v;
449 off_t offset;
450 int prot;
451 {
452 struct sfb_softc *sc = v;
453
454 if (offset >= 0x1000000 || offset < 0)
455 return (-1);
456 return machine_btop(sc->sc_dc->dc_paddr + offset);
457 }
458
459 int
460 sfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
461 void *v;
462 const struct wsscreen_descr *type;
463 void **cookiep;
464 int *curxp, *curyp;
465 long *attrp;
466 {
467 struct sfb_softc *sc = v;
468 long defattr;
469
470 if (sc->nscreens > 0)
471 return (ENOMEM);
472
473 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
474 *curxp = 0;
475 *curyp = 0;
476 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
477 *attrp = defattr;
478 sc->nscreens++;
479 return (0);
480 }
481
482 void
483 sfb_free_screen(v, cookie)
484 void *v;
485 void *cookie;
486 {
487 struct sfb_softc *sc = v;
488
489 if (sc->sc_dc == &sfb_console_dc)
490 panic("sfb_free_screen: console");
491
492 sc->nscreens--;
493 }
494
495 void
496 sfb_show_screen(v, cookie)
497 void *v;
498 void *cookie;
499 {
500 }
501
502 int
503 sfb_cnattach(addr)
504 tc_addr_t addr;
505 {
506 struct fb_devconfig *dcp = &sfb_console_dc;
507 long defattr;
508
509 sfb_getdevconfig(addr, dcp);
510
511 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
512
513 wsdisplay_cnattach(&sfb_stdscreen, &dcp->dc_rcons,
514 0, 0, defattr);
515 sfb_consaddr = addr;
516 return(0);
517 }
518
519 int
520 sfbintr(arg)
521 void *arg;
522 {
523 struct sfb_softc *sc = arg;
524 caddr_t sfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
525 caddr_t sfbasic = sfbbase + SFB_ASIC_OFFSET;
526 struct bt459reg *vdac;
527 int v;
528
529 *(u_int32_t *)(sfbasic + SFB_ASIC_CLEAR_INTR) = 0;
530 /* *(u_int32_t *)(sfbasic + SFB_ASIC_ENABLE_INTR) = 1; */
531
532 if (sc->sc_changed == 0)
533 return (1);
534
535 vdac = (void *)(sfbbase + SFB_RAMDAC_OFFSET);
536 v = sc->sc_changed;
537 sc->sc_changed = 0;
538
539 if (v & DATA_ENB_CHANGED) {
540 BT459_SELECT(vdac, BT459_REG_CCR);
541 vdac->bt_reg = (sc->sc_curenb) ? 0xc0 : 0x00;
542 }
543 if (v & DATA_CURCMAP_CHANGED) {
544 u_int8_t *cp = sc->sc_cursor.cc_color;
545
546 BT459_SELECT(vdac, BT459_REG_CCOLOR_2);
547 vdac->bt_reg = cp[1]; tc_wmb();
548 vdac->bt_reg = cp[3]; tc_wmb();
549 vdac->bt_reg = cp[5]; tc_wmb();
550
551 vdac->bt_reg = cp[0]; tc_wmb();
552 vdac->bt_reg = cp[2]; tc_wmb();
553 vdac->bt_reg = cp[4]; tc_wmb();
554 }
555 if (v & DATA_CURSHAPE_CHANGED) {
556 u_int8_t *ip, *mp, img, msk;
557 u_int8_t u;
558 int bcnt;
559
560 ip = (u_int8_t *)sc->sc_cursor.cc_image;
561 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
562
563 bcnt = 0;
564 BT459_SELECT(vdac, BT459_REG_CRAM_BASE+0);
565 /* 64 pixel scan line is consisted with 16 byte cursor ram */
566 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
567 /* pad right half 32 pixel when smaller than 33 */
568 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
569 vdac->bt_reg = 0; tc_wmb();
570 vdac->bt_reg = 0; tc_wmb();
571 }
572 else {
573 img = *ip++;
574 msk = *mp++;
575 img &= msk; /* cookie off image */
576 u = (msk & 0x0f) << 4 | (img & 0x0f);
577 vdac->bt_reg = shuffle[u]; tc_wmb();
578 u = (msk & 0xf0) | (img & 0xf0) >> 4;
579 vdac->bt_reg = shuffle[u]; tc_wmb();
580 }
581 bcnt += 2;
582 }
583 /* pad unoccupied scan lines */
584 while (bcnt < CURSOR_MAX_SIZE * 16) {
585 vdac->bt_reg = 0; tc_wmb();
586 vdac->bt_reg = 0; tc_wmb();
587 bcnt += 2;
588 }
589 }
590 if (v & DATA_CMAP_CHANGED) {
591 struct hwcmap *cm = &sc->sc_cmap;
592 int index;
593
594 BT459_SELECT(vdac, 0);
595 for (index = 0; index < CMAP_SIZE; index++) {
596 vdac->bt_cmap = cm->r[index]; tc_wmb();
597 vdac->bt_cmap = cm->g[index]; tc_wmb();
598 vdac->bt_cmap = cm->b[index]; tc_wmb();
599 }
600 }
601 return (1);
602 }
603
604 void
605 sfbinit(dc)
606 struct fb_devconfig *dc;
607 {
608 caddr_t sfbasic = (caddr_t)(dc->dc_vaddr + SFB_ASIC_OFFSET);
609 struct bt459reg *vdac = (void *)(dc->dc_vaddr + SFB_RAMDAC_OFFSET);
610 int i;
611
612 *(u_int32_t *)(sfbasic + SFB_ASIC_VIDEO_VALID) = 0;
613 *(u_int32_t *)(sfbasic + SFB_ASIC_PLANEMASK) = ~0;
614 *(u_int32_t *)(sfbasic + SFB_ASIC_PIXELMASK) = ~0;
615 *(u_int32_t *)(sfbasic + SFB_ASIC_MODE) = 0;
616 *(u_int32_t *)(sfbasic + SFB_ASCI_ROP) = 3;
617
618 *(u_int32_t *)(sfbasic + 0x180000) = 0; /* Bt459 reset */
619
620 BT459_SELECT(vdac, BT459_REG_COMMAND_0);
621 vdac->bt_reg = 0x40; /* CMD0 */ tc_wmb();
622 vdac->bt_reg = 0x0; /* CMD1 */ tc_wmb();
623 vdac->bt_reg = 0xc0; /* CMD2 */ tc_wmb();
624 vdac->bt_reg = 0xff; /* PRM */ tc_wmb();
625 vdac->bt_reg = 0; /* 205 */ tc_wmb();
626 vdac->bt_reg = 0x0; /* PBM */ tc_wmb();
627 vdac->bt_reg = 0; /* 207 */ tc_wmb();
628 vdac->bt_reg = 0x0; /* ORM */ tc_wmb();
629 vdac->bt_reg = 0x0; /* OBM */ tc_wmb();
630 vdac->bt_reg = 0x0; /* ILV */ tc_wmb();
631 vdac->bt_reg = 0x0; /* TEST */ tc_wmb();
632
633 BT459_SELECT(vdac, BT459_REG_CCR);
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 vdac->bt_reg = 0x0; tc_wmb();
645 vdac->bt_reg = 0x0; tc_wmb();
646 vdac->bt_reg = 0x0; tc_wmb();
647
648 /* build sane colormap */
649 BT459_SELECT(vdac, 0);
650 vdac->bt_cmap = 0; tc_wmb();
651 vdac->bt_cmap = 0; tc_wmb();
652 vdac->bt_cmap = 0; tc_wmb();
653 for (i = 1; i < CMAP_SIZE; i++) {
654 vdac->bt_cmap = 0xff; tc_wmb();
655 vdac->bt_cmap = 0xff; tc_wmb();
656 vdac->bt_cmap = 0xff; tc_wmb();
657 }
658
659 /* clear out cursor image */
660 BT459_SELECT(vdac, BT459_REG_CRAM_BASE);
661 for (i = 0; i < 1024; i++)
662 vdac->bt_reg = 0xff; tc_wmb();
663
664 /*
665 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
666 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for
667 * image color. CCOLOR_1 will be never used.
668 */
669 BT459_SELECT(vdac, BT459_REG_CCOLOR_1);
670 vdac->bt_reg = 0xff; tc_wmb();
671 vdac->bt_reg = 0xff; tc_wmb();
672 vdac->bt_reg = 0xff; tc_wmb();
673
674 vdac->bt_reg = 0; tc_wmb();
675 vdac->bt_reg = 0; tc_wmb();
676 vdac->bt_reg = 0; tc_wmb();
677
678 vdac->bt_reg = 0xff; tc_wmb();
679 vdac->bt_reg = 0xff; tc_wmb();
680 vdac->bt_reg = 0xff; tc_wmb();
681 }
682
683 static int
684 get_cmap(sc, p)
685 struct sfb_softc *sc;
686 struct wsdisplay_cmap *p;
687 {
688 u_int index = p->index, count = p->count;
689
690 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
691 return (EINVAL);
692
693 if (!useracc(p->red, count, B_WRITE) ||
694 !useracc(p->green, count, B_WRITE) ||
695 !useracc(p->blue, count, B_WRITE))
696 return (EFAULT);
697
698 copyout(&sc->sc_cmap.r[index], p->red, count);
699 copyout(&sc->sc_cmap.g[index], p->green, count);
700 copyout(&sc->sc_cmap.b[index], p->blue, count);
701
702 return (0);
703 }
704
705 static int
706 set_cmap(sc, p)
707 struct sfb_softc *sc;
708 struct wsdisplay_cmap *p;
709 {
710 u_int index = p->index, count = p->count;
711
712 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
713 return (EINVAL);
714
715 if (!useracc(p->red, count, B_READ) ||
716 !useracc(p->green, count, B_READ) ||
717 !useracc(p->blue, count, B_READ))
718 return (EFAULT);
719
720 copyin(p->red, &sc->sc_cmap.r[index], count);
721 copyin(p->green, &sc->sc_cmap.g[index], count);
722 copyin(p->blue, &sc->sc_cmap.b[index], count);
723
724 sc->sc_changed |= DATA_CMAP_CHANGED;
725
726 return (0);
727 }
728
729
730 static int
731 set_cursor(sc, p)
732 struct sfb_softc *sc;
733 struct wsdisplay_cursor *p;
734 {
735 #define cc (&sc->sc_cursor)
736 int v, index, count, icount;
737
738 v = p->which;
739 if (v & WSDISPLAY_CURSOR_DOCMAP) {
740 index = p->cmap.index;
741 count = p->cmap.count;
742 if (index >= 2 || (index + count) > 2)
743 return (EINVAL);
744 if (!useracc(p->cmap.red, count, B_READ) ||
745 !useracc(p->cmap.green, count, B_READ) ||
746 !useracc(p->cmap.blue, count, B_READ))
747 return (EFAULT);
748 }
749 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
750 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
751 return (EINVAL);
752 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
753 if (!useracc(p->image, count, B_READ) ||
754 !useracc(p->mask, count, B_READ))
755 return (EFAULT);
756 }
757 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
758 if (v & WSDISPLAY_CURSOR_DOCUR)
759 cc->cc_hot = p->hot;
760 if (v & WSDISPLAY_CURSOR_DOPOS)
761 set_curpos(sc, &p->pos);
762 bt459_set_curpos(sc);
763 }
764
765 sc->sc_changed = 0;
766 if (v & WSDISPLAY_CURSOR_DOCUR) {
767 sc->sc_curenb = p->enable;
768 sc->sc_changed |= DATA_ENB_CHANGED;
769 }
770 if (v & WSDISPLAY_CURSOR_DOCMAP) {
771 copyin(p->cmap.red, &cc->cc_color[index], count);
772 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
773 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
774 sc->sc_changed |= DATA_CURCMAP_CHANGED;
775 }
776 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
777 cc->cc_size = p->size;
778 memset(cc->cc_image, 0, sizeof cc->cc_image);
779 copyin(p->image, cc->cc_image, icount);
780 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
781 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
782 }
783
784 return (0);
785 #undef cc
786 }
787
788 static int
789 get_cursor(sc, p)
790 struct sfb_softc *sc;
791 struct wsdisplay_cursor *p;
792 {
793 return (ENOTTY); /* XXX */
794 }
795
796 static void
797 set_curpos(sc, curpos)
798 struct sfb_softc *sc;
799 struct wsdisplay_curpos *curpos;
800 {
801 struct fb_devconfig *dc = sc->sc_dc;
802 int x = curpos->x, y = curpos->y;
803
804 if (y < 0)
805 y = 0;
806 else if (y > dc->dc_ht)
807 y = dc->dc_ht;
808 if (x < 0)
809 x = 0;
810 else if (x > dc->dc_wid)
811 x = dc->dc_wid;
812 sc->sc_cursor.cc_pos.x = x;
813 sc->sc_cursor.cc_pos.y = y;
814 }
815
816 static void
817 bt459_set_curpos(sc)
818 struct sfb_softc *sc;
819 {
820 caddr_t sfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
821 struct bt459reg *vdac = (void *)(sfbbase + SFB_RAMDAC_OFFSET);
822 int x, y, s;
823
824 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
825 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
826 x += sc->magic_x; y += sc->magic_y; /* magic offset of HX coordinate */
827
828 s = spltty();
829
830 BT459_SELECT(vdac, BT459_REG_CURSOR_X_LOW);
831 vdac->bt_reg = x; tc_wmb();
832 vdac->bt_reg = x >> 8; tc_wmb();
833 vdac->bt_reg = y; tc_wmb();
834 vdac->bt_reg = y >> 8; tc_wmb();
835
836 splx(s);
837 }
838