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