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