1 /* $NetBSD: stic.c,v 1.45 2008/07/09 13:19:33 joerg Exp $ */
4 * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Driver for the DEC PixelStamp interface chip (STIC).
35 * XXX The bt459 interface shouldn't be replicated here.
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: stic.c,v 1.45 2008/07/09 13:19:33 joerg Exp $");
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/device.h>
45 #include <sys/malloc.h>
47 #include <sys/ioctl.h>
48 #include <sys/callout.h>
50 #include <sys/kauth.h>
52 #include <sys/event.h>
54 #include <uvm/uvm_extern.h>
57 #include <mips/cpuregs.h>
59 #include <alpha/alpha_cpu.h>
62 #include <machine/vmparam.h>
66 #include <dev/wscons/wsconsio.h>
67 #include <dev/wscons/wsdisplayvar.h>
69 #include <dev/wsfont/wsfont.h>
71 #include <dev/ic/bt459reg.h>
73 #include <dev/tc/tcvar.h>
74 #include <dev/tc/sticreg.h>
75 #include <dev/tc/sticio.h>
76 #include <dev/tc/sticvar.h>
78 #define DUPBYTE0(x) ((((x)&0xff)<<16) | (((x)&0xff)<<8) | ((x)&0xff))
79 #define DUPBYTE1(x) ((((x)<<8)&0xff0000) | ((x)&0xff00) | (((x)>>8)&0xff))
80 #define DUPBYTE2(x) (((x)&0xff0000) | (((x)>>8)&0xff00) | (((x)>>16)&0xff))
82 #define PACK(p, o) ((p)[(o)] | ((p)[(o)+1] << 16))
85 #define machine_btop(x) mips_btop(x)
87 #define machine_btop(x) alpha_btop(x)
91 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have
92 * obscure register layout such as 2nd and 3rd Bt459 registers are
93 * adjacent each other in a word, i.e.,
94 * struct bt459triplet {
103 * Although HX has single Bt459, 32bit R/W can be done w/o any trouble.
113 /* Bt459 hardware registers */
119 #define REG(base, index) *((volatile uint32_t *)(base) + (index))
120 #define SELECT(vdac, regno) do { \
121 REG(vdac, bt_lo) = DUPBYTE0(regno); \
122 REG(vdac, bt_hi) = DUPBYTE1(regno); \
126 static int sticioctl(void *, void *, u_long
, void *, int, struct lwp
*);
127 static int stic_alloc_screen(void *, const struct wsscreen_descr
*,
128 void **, int *, int *, long *);
129 static void stic_free_screen(void *, void *);
130 static int stic_show_screen(void *, void *, int,
131 void (*)(void *, int, int), void *);
133 static void stic_do_switch(void *);
134 static void stic_setup_backing(struct stic_info
*, struct stic_screen
*);
135 static void stic_setup_vdac(struct stic_info
*);
136 static void stic_clear_screen(struct stic_info
*);
138 static int stic_get_cmap(struct stic_info
*, struct wsdisplay_cmap
*);
139 static int stic_set_cmap(struct stic_info
*, struct wsdisplay_cmap
*);
140 static int stic_set_cursor(struct stic_info
*, struct wsdisplay_cursor
*);
141 static int stic_get_cursor(struct stic_info
*, struct wsdisplay_cursor
*);
142 static void stic_set_curpos(struct stic_info
*, struct wsdisplay_curpos
*);
143 static void stic_set_hwcurpos(struct stic_info
*);
145 static void stic_cursor(void *, int, int, int);
146 static void stic_copycols(void *, int, int, int, int);
147 static void stic_copyrows(void *, int, int, int);
148 static void stic_erasecols(void *, int, int, int, long);
149 static void stic_eraserows(void *, int, int, long);
150 static int stic_mapchar(void *, int, u_int
*);
151 static void stic_putchar(void *, int, int, u_int
, long);
152 static int stic_allocattr(void *, int, int, int, long *);
154 static dev_type_open(sticopen
);
155 static dev_type_close(sticclose
);
156 static dev_type_mmap(sticmmap
);
158 const struct cdevsw stic_cdevsw
= {
159 sticopen
, sticclose
, noread
, nowrite
, noioctl
,
160 nostop
, notty
, nopoll
, sticmmap
, nokqfilter
,
163 /* Colormap for wscons, matching WSCOL_*. Upper 8 are high-intensity. */
164 static const uint8_t stic_cmap
[16*3] = {
165 0x00, 0x00, 0x00, /* black */
166 0x7f, 0x00, 0x00, /* red */
167 0x00, 0x7f, 0x00, /* green */
168 0x7f, 0x7f, 0x00, /* brown */
169 0x00, 0x00, 0x7f, /* blue */
170 0x7f, 0x00, 0x7f, /* magenta */
171 0x00, 0x7f, 0x7f, /* cyan */
172 0xc7, 0xc7, 0xc7, /* white */
174 0x7f, 0x7f, 0x7f, /* black */
175 0xff, 0x00, 0x00, /* red */
176 0x00, 0xff, 0x00, /* green */
177 0xff, 0xff, 0x00, /* brown */
178 0x00, 0x00, 0xff, /* blue */
179 0xff, 0x00, 0xff, /* magenta */
180 0x00, 0xff, 0xff, /* cyan */
181 0xff, 0xff, 0xff, /* white */
185 * Compose 2 bit/pixel cursor image. Bit order will be reversed.
186 * M M M M I I I I M I M I M I M I
187 * [ before ] [ after ]
188 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3
189 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7
191 static const uint8_t shuffle
[256] = {
192 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
193 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
194 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
195 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
196 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
197 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
198 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
199 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
200 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
201 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
202 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
203 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
204 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
205 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
206 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
207 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
208 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
209 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
210 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
211 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
212 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
213 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
214 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
215 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
216 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
217 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
218 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
219 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
220 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
221 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
222 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
223 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
226 static const struct wsdisplay_accessops stic_accessops
= {
232 NULL
, /* load_font */
235 static const struct wsdisplay_emulops stic_emulops
= {
246 static struct wsscreen_descr stic_stdscreen
= {
251 WSSCREEN_WSCOLORS
| WSSCREEN_HILIT
254 static const struct wsscreen_descr
*_stic_scrlist
[] = {
258 static const struct wsscreen_list stic_screenlist
= {
259 sizeof(_stic_scrlist
) / sizeof(struct wsscreen_descr
*), _stic_scrlist
262 struct stic_info stic_consinfo
;
263 static struct stic_screen stic_consscr
;
264 static struct stic_info
*stic_info
[STIC_MAXDV
];
265 static int stic_unit
;
268 stic_init(struct stic_info
*si
)
270 volatile uint32_t *vdac
;
273 /* Reset the STIC & stamp(s). */
278 SELECT(vdac
, BT459_IREG_COMMAND_0
);
279 REG(vdac
, bt_reg
) = 0x00c0c0c0; tc_wmb();
281 /* Now reset the VDAC. */
282 *si
->si_vdac_reset
= 0;
287 /* Finish the initialization. */
288 SELECT(vdac
, BT459_IREG_COMMAND_1
);
289 REG(vdac
, bt_reg
) = 0x00000000; tc_wmb();
290 REG(vdac
, bt_reg
) = 0x00c2c2c2; tc_wmb();
291 REG(vdac
, bt_reg
) = 0x00ffffff; tc_wmb();
293 for (i
= 0; i
< 7; i
++) {
294 REG(vdac
, bt_reg
) = 0x00000000;
298 /* Set cursor colormap. */
299 SELECT(vdac
, BT459_IREG_CCOLOR_1
);
300 REG(vdac
, bt_reg
) = 0x00ffffff; tc_wmb();
301 REG(vdac
, bt_reg
) = 0x00ffffff; tc_wmb();
302 REG(vdac
, bt_reg
) = 0x00ffffff; tc_wmb();
303 REG(vdac
, bt_reg
) = 0x00000000; tc_wmb();
304 REG(vdac
, bt_reg
) = 0x00000000; tc_wmb();
305 REG(vdac
, bt_reg
) = 0x00000000; tc_wmb();
306 REG(vdac
, bt_reg
) = 0x00ffffff; tc_wmb();
307 REG(vdac
, bt_reg
) = 0x00ffffff; tc_wmb();
308 REG(vdac
, bt_reg
) = 0x00ffffff; tc_wmb();
310 /* Get a font and set up screen metrics. */
313 cookie
= wsfont_find(NULL
, 12, 0, 2, WSDISPLAY_FONTORDER_R2L
,
314 WSDISPLAY_FONTORDER_L2R
);
316 cookie
= wsfont_find(NULL
, 0, 0, 2, WSDISPLAY_FONTORDER_R2L
,
317 WSDISPLAY_FONTORDER_L2R
);
319 panic("stic_init: font table is empty");
321 if (wsfont_lock(cookie
, &si
->si_font
))
322 panic("stic_init: couldn't lock font");
324 si
->si_fontw
= si
->si_font
->fontwidth
;
325 si
->si_fonth
= si
->si_font
->fontheight
;
326 si
->si_consw
= (1280 / si
->si_fontw
) & ~1;
327 si
->si_consh
= 1024 / si
->si_fonth
;
328 stic_stdscreen
.ncols
= si
->si_consw
;
329 stic_stdscreen
.nrows
= si
->si_consh
;
332 if ((u_int
)si
->si_fonth
> 32 || (u_int
)si
->si_fontw
> 16)
333 panic("stic_init: unusable font");
337 stic_clear_screen(si
);
338 si
->si_dispmode
= WSDISPLAYIO_MODE_EMUL
;
342 stic_reset(struct stic_info
*si
)
344 int modtype
, xconfig
, yconfig
, config
;
345 volatile struct stic_regs
*sr
;
350 * Initialize the interface chip registers.
352 sr
->sr_sticsr
= 0x00000030; /* Get the STIC's attention. */
355 DELAY(2000); /* wait 2ms for STIC to respond. */
356 sr
->sr_sticsr
= 0x00000000; /* Hit the STIC's csr again... */
358 sr
->sr_buscsr
= 0xffffffff; /* and bash its bus-acess csr. */
360 tc_syncbus(); /* Blam! */
361 DELAY(20000); /* wait until the stic recovers... */
363 modtype
= sr
->sr_modcl
;
364 xconfig
= (modtype
& 0x800) >> 11;
365 yconfig
= (modtype
& 0x600) >> 9;
366 config
= (yconfig
<< 1) | xconfig
;
367 si
->si_stampw
= (xconfig
? 5 : 4);
368 si
->si_stamph
= (1 << yconfig
);
369 si
->si_stamphm
= si
->si_stamph
- 1;
371 si
->si_option
= (char)((modtype
>> 12) & 3);
374 /* First PixelStamp */
375 si
->si_stamp
[0x000b0] = config
;
376 si
->si_stamp
[0x000b4] = 0x0;
378 /* Second PixelStamp */
380 si
->si_stamp
[0x100b0] = config
| 8;
381 si
->si_stamp
[0x100b4] = 0;
385 * Initialize STIC video registers. Enable error and vertical
386 * retrace interrupts. Set the packet done flag so the Xserver will
387 * not time-out on the first packet submitted.
389 sr
->sr_vblank
= (1024 << 16) | 1063;
390 sr
->sr_vsync
= (1027 << 16) | 1030;
391 sr
->sr_hblank
= (255 << 16) | 340;
393 sr
->sr_hsync
= (261 << 16) | 293;
395 STIC_INT_WE
| STIC_INT_P
| STIC_INT_E_EN
| STIC_INT_V_EN
;
402 stic_attach(device_t self
, struct stic_info
*si
, int console
)
404 struct wsemuldisplaydev_attach_args waa
;
406 if (stic_unit
< STIC_MAXDV
) {
407 stic_info
[stic_unit
] = si
;
408 si
->si_unit
= stic_unit
++;
412 callout_init(&si
->si_switch_callout
, 0);
415 * Allocate backing for the console. We could trawl back through
416 * msgbuf and and fill the backing, but it's not worth the hassle.
417 * We could also grab backing using pmap_steal_memory() early on,
418 * but that's a little ugly.
421 stic_setup_backing(si
, &stic_consscr
);
423 waa
.console
= console
;
424 waa
.scrdata
= &stic_screenlist
;
425 waa
.accessops
= &stic_accessops
;
426 waa
.accesscookie
= si
;
428 config_found(self
, &waa
, wsemuldisplaydevprint
);
432 stic_cnattach(struct stic_info
*si
)
434 struct stic_screen
*ss
;
438 si
->si_curscreen
= ss
;
439 ss
->ss_flags
= SS_ALLOCED
| SS_ACTIVE
| SS_CURENB
;
442 si
->si_flags
|= SI_CURENB_CHANGED
;
445 stic_allocattr(ss
, 0, 0, 0, &defattr
);
446 stic_eraserows(ss
, 0, si
->si_consh
, 0);
447 wsdisplay_cnattach(&stic_stdscreen
, ss
, 0, 0, defattr
);
451 stic_setup_vdac(struct stic_info
*si
)
454 int r
, c
, o
, b
, i
, s
;
458 ip
= (uint8_t *)si
->si_cursor
.cc_image
;
459 mp
= (uint8_t *)si
->si_cursor
.cc_mask
;
460 memset(ip
, 0, sizeof(si
->si_cursor
.cc_image
));
461 memset(mp
, 0, sizeof(si
->si_cursor
.cc_mask
));
463 for (r
= 0; r
< si
->si_fonth
; r
++) {
464 for (c
= r
& 1; c
< si
->si_fontw
; c
+= 2) {
475 si
->si_cursor
.cc_size
.x
= 64;
476 si
->si_cursor
.cc_size
.y
= si
->si_fonth
;
477 si
->si_cursor
.cc_hot
.x
= 0;
478 si
->si_cursor
.cc_hot
.y
= 0;
480 si
->si_cursor
.cc_color
[0] = 0xff;
481 si
->si_cursor
.cc_color
[2] = 0xff;
482 si
->si_cursor
.cc_color
[4] = 0xff;
483 si
->si_cursor
.cc_color
[1] = 0x00;
484 si
->si_cursor
.cc_color
[3] = 0x00;
485 si
->si_cursor
.cc_color
[5] = 0x00;
487 memset(&si
->si_cmap
, 0, sizeof(si
->si_cmap
));
488 for (i
= 0; i
< 16; i
++) {
489 si
->si_cmap
.r
[i
] = stic_cmap
[i
*3 + 0];
490 si
->si_cmap
.g
[i
] = stic_cmap
[i
*3 + 1];
491 si
->si_cmap
.b
[i
] = stic_cmap
[i
*3 + 2];
494 si
->si_flags
|= SI_CMAP_CHANGED
| SI_CURSHAPE_CHANGED
|
501 stic_clear_screen(struct stic_info
*si
)
507 * Do this twice, since the first packet after a reset may be
510 for (i
= 0; i
< 2; i
++) {
511 pb
= (*si
->si_pbuf_get
)(si
);
513 pb
[0] = STAMP_CMD_LINES
| STAMP_RGB_CONST
| STAMP_LW_PERPACKET
;
516 pb
[3] = STAMP_UPDATE_ENABLE
| STAMP_METHOD_COPY
;
517 pb
[4] = (1024 << 2) - 1;
520 pb
[7] = (1280 << 19) | ((1024 << 3) + pb
[4]);
522 (*si
->si_pbuf_post
)(si
, pb
);
527 sticioctl(void *v
, void *vs
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
529 struct stic_info
*si
;
535 case WSDISPLAYIO_GTYPE
:
536 *(u_int
*)data
= si
->si_disptype
;
539 case WSDISPLAYIO_GINFO
:
540 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
541 wsd_fbip
->height
= 1024;
542 wsd_fbip
->width
= 1280;
543 wsd_fbip
->depth
= si
->si_depth
== 8 ? 8 : 32;
544 wsd_fbip
->cmsize
= CMAP_SIZE
;
548 case WSDISPLAYIO_GETCMAP
:
549 return (stic_get_cmap(si
, (struct wsdisplay_cmap
*)data
));
551 case WSDISPLAYIO_PUTCMAP
:
552 return (stic_set_cmap(si
, (struct wsdisplay_cmap
*)data
));
554 case WSDISPLAYIO_SVIDEO
:
555 #if 0 /* XXX later */
556 turnoff
= *(int *)data
== WSDISPLAYIO_VIDEO_OFF
;
557 if ((si
->si_blanked
== 0) ^ turnoff
)
558 si
->si_blanked
= turnoff
;
562 case WSDISPLAYIO_GVIDEO
:
563 #if 0 /* XXX later */
564 *(u_int
*)data
= si
->si_blanked
?
565 WSDISPLAYIO_VIDEO_OFF
: WSDISPLAYIO_VIDEO_ON
;
569 case WSDISPLAYIO_GCURPOS
:
570 *(struct wsdisplay_curpos
*)data
= si
->si_cursor
.cc_pos
;
573 case WSDISPLAYIO_SCURPOS
:
574 stic_set_curpos(si
, (struct wsdisplay_curpos
*)data
);
577 case WSDISPLAYIO_GCURMAX
:
578 ((struct wsdisplay_curpos
*)data
)->x
=
579 ((struct wsdisplay_curpos
*)data
)->y
= CURSOR_MAX_SIZE
;
582 case WSDISPLAYIO_GCURSOR
:
583 return (stic_get_cursor(si
, (struct wsdisplay_cursor
*)data
));
585 case WSDISPLAYIO_SCURSOR
:
586 return (stic_set_cursor(si
, (struct wsdisplay_cursor
*)data
));
588 case WSDISPLAYIO_SMODE
:
589 si
->si_dispmode
= *(int *)data
;
590 if (si
->si_dispmode
== WSDISPLAYIO_MODE_EMUL
) {
591 (*si
->si_ioctl
)(si
, STICIO_STOPQ
, NULL
, flag
, l
);
596 stic_clear_screen(si
);
597 stic_do_switch(si
->si_curscreen
);
606 if (si
->si_ioctl
!= NULL
)
607 return ((*si
->si_ioctl
)(si
, cmd
, data
, flag
, l
));
609 return (EPASSTHROUGH
);
613 stic_setup_backing(struct stic_info
*si
, struct stic_screen
*ss
)
617 size
= si
->si_consw
* si
->si_consh
* sizeof(*ss
->ss_backing
);
618 ss
->ss_backing
= malloc(size
, M_DEVBUF
, M_NOWAIT
|M_ZERO
);
622 stic_alloc_screen(void *v
, const struct wsscreen_descr
*type
, void **cookiep
,
623 int *curxp
, int *curyp
, long *attrp
)
625 struct stic_info
*si
;
626 struct stic_screen
*ss
;
628 si
= (struct stic_info
*)v
;
630 if ((stic_consscr
.ss_flags
& SS_ALLOCED
) == 0)
633 ss
= malloc(sizeof(*ss
), M_DEVBUF
, M_WAITOK
|M_ZERO
);
635 stic_setup_backing(si
, ss
);
638 ss
->ss_flags
= SS_ALLOCED
| SS_CURENB
;
644 stic_allocattr(ss
, 0, 0, 0, attrp
);
649 stic_free_screen(void *v
, void *cookie
)
651 struct stic_screen
*ss
;
656 if (ss
== &stic_consscr
)
657 panic("stic_free_screen: console");
658 if (ss
== ((struct stic_info
*)v
)->si_curscreen
)
659 panic("stic_free_screen: freeing current screen");
662 free(ss
->ss_backing
, M_DEVBUF
);
667 stic_show_screen(void *v
, void *cookie
, int waitok
,
668 void (*cb
)(void *, int, int), void *cbarg
)
670 struct stic_info
*si
;
672 si
= (struct stic_info
*)v
;
673 if (si
->si_switchcbarg
!= NULL
)
675 si
->si_switchcb
= cb
;
676 si
->si_switchcbarg
= cbarg
;
679 callout_reset(&si
->si_switch_callout
, 0, stic_do_switch
,
684 stic_do_switch(cookie
);
689 stic_do_switch(void *cookie
)
691 struct stic_screen
*ss
;
692 struct stic_info
*si
;
700 if (ss
->ss_backing
== NULL
)
701 panic("stic_do_switch: screen not backed");
704 /* Swap in the new screen, and temporarily disable its backing. */
705 if (si
->si_curscreen
!= NULL
)
706 si
->si_curscreen
->ss_flags
^= SS_ACTIVE
;
707 si
->si_curscreen
= ss
;
708 ss
->ss_flags
|= SS_ACTIVE
;
710 ss
->ss_backing
= NULL
;
713 * We assume that most of the screen is blank and blast it with
714 * eraserows(), because eraserows() is cheap.
717 stic_eraserows(ss
, 0, nr
, 0);
721 for (r
= 0; r
< nr
; r
++)
722 for (c
= 0; c
< nc
; c
+= 2, p
+= 2) {
723 if ((p
[0] & 0xfff0) != 0)
724 stic_putchar(ss
, r
, c
, p
[0] >> 8,
726 if ((p
[1] & 0xfff0) != 0)
727 stic_putchar(ss
, r
, c
+ 1, p
[1] >> 8,
732 * Re-enable the screen's backing, and move the cursor to the
736 si
->si_cursor
.cc_pos
.x
= ss
->ss_curx
;
737 si
->si_cursor
.cc_pos
.y
= ss
->ss_cury
;
738 stic_set_hwcurpos(si
);
739 si
->si_flags
|= SI_CURENB_CHANGED
;
742 * XXX Since we don't yet receive vblank interrupts from the
743 * PXG, we must flush immediatley.
745 if (si
->si_disptype
== WSDISPLAY_TYPE_PXG
)
748 /* Tell wscons that we're done. */
749 if (si
->si_switchcbarg
!= NULL
) {
750 cookie
= si
->si_switchcbarg
;
751 si
->si_switchcbarg
= NULL
;
752 (*si
->si_switchcb
)(cookie
, 0, 0);
757 stic_allocattr(void *cookie
, int fg
, int bg
, int flags
, long *attr
)
761 if ((flags
& (WSATTR_BLINK
| WSATTR_UNDERLINE
)) != 0)
764 if ((flags
& WSATTR_WSCOLORS
) == 0) {
769 if ((flags
& WSATTR_HILIT
) != 0)
772 tmp
= fg
| (bg
<< 4);
773 *attr
= tmp
| (tmp
<< 16);
778 stic_erasecols(void *cookie
, int row
, int col
, int num
, long attr
)
780 struct stic_info
*si
;
781 struct stic_screen
*ss
;
789 if (ss
->ss_backing
!= NULL
) {
790 p
= ss
->ss_backing
+ row
* si
->si_consw
+ col
;
791 for (i
= num
; i
!= 0; i
--)
792 *p
++ = (uint16_t)attr
;
794 if ((ss
->ss_flags
& SS_ACTIVE
) == 0)
797 col
= (col
* si
->si_fontw
) << 19;
798 num
= (num
* si
->si_fontw
) << 19;
799 row
= row
* si
->si_fonth
;
800 attr
= (attr
& 0xf0) >> 4;
801 linewidth
= (si
->si_fonth
<< 2) - 1;
802 row
= (row
<< 3) + linewidth
;
804 pb
= (*si
->si_pbuf_get
)(si
);
806 pb
[0] = STAMP_CMD_LINES
| STAMP_RGB_CONST
| STAMP_LW_PERPACKET
;
809 pb
[3] = STAMP_UPDATE_ENABLE
| STAMP_METHOD_COPY
;
811 pb
[5] = DUPBYTE0(attr
);
813 pb
[7] = (col
+ num
) | row
;
815 (*si
->si_pbuf_post
)(si
, pb
);
819 stic_eraserows(void *cookie
, int row
, int num
, long attr
)
821 struct stic_info
*si
;
822 struct stic_screen
*ss
;
829 if (ss
->ss_backing
!= NULL
) {
830 pb
= (uint32_t *)(ss
->ss_backing
+ row
* si
->si_consw
);
831 for (i
= si
->si_consw
* num
; i
> 0; i
-= 2)
832 *pb
++ = (uint32_t)attr
;
834 if ((ss
->ss_flags
& SS_ACTIVE
) == 0)
839 attr
= (attr
& 0xf0) >> 4;
840 linewidth
= (num
<< 2) - 1;
841 row
= (row
<< 3) + linewidth
;
843 pb
= (*si
->si_pbuf_get
)(si
);
845 pb
[0] = STAMP_CMD_LINES
| STAMP_RGB_CONST
| STAMP_LW_PERPACKET
;
848 pb
[3] = STAMP_UPDATE_ENABLE
| STAMP_METHOD_COPY
;
850 pb
[5] = DUPBYTE0(attr
);
852 pb
[7] = (1280 << 19) | row
;
854 (*si
->si_pbuf_post
)(si
, pb
);
858 stic_copyrows(void *cookie
, int src
, int dst
, int height
)
860 struct stic_info
*si
;
861 struct stic_screen
*ss
;
868 if (ss
->ss_backing
!= NULL
)
869 bcopy(ss
->ss_backing
+ src
* si
->si_consw
,
870 ss
->ss_backing
+ dst
* si
->si_consw
,
871 si
->si_consw
* sizeof(*ss
->ss_backing
) * height
);
872 if ((ss
->ss_flags
& SS_ACTIVE
) == 0)
876 * We need to do this in reverse if the destination row is below
889 src
= (src
* si
->si_fonth
+ adj
) << 3;
890 dst
= (dst
* si
->si_fonth
+ adj
) << 3;
891 height
*= si
->si_fonth
;
894 num
= (height
< 255 ? height
: 255);
897 pbs
= (*si
->si_pbuf_get
)(si
);
900 pb
[0] = STAMP_CMD_COPYSPANS
| STAMP_LW_PERPACKET
;
901 pb
[1] = (num
<< 24) | 0xffffff;
903 pb
[3] = STAMP_UPDATE_ENABLE
| STAMP_METHOD_COPY
| STAMP_SPAN
|
904 STAMP_COPYSPAN_ALIGNED
;
905 pb
[4] = 1; /* linewidth */
907 for (; num
!= 0; num
--, src
+= inc
, dst
+= inc
, pb
+= 3) {
913 (*si
->si_pbuf_post
)(si
, pbs
);
918 stic_copycols(void *cookie
, int row
, int src
, int dst
, int num
)
920 struct stic_info
*si
;
921 struct stic_screen
*ss
;
922 u_int height
, updword
;
928 if (ss
->ss_backing
!= NULL
)
929 bcopy(ss
->ss_backing
+ row
* si
->si_consw
+ src
,
930 ss
->ss_backing
+ row
* si
->si_consw
+ dst
,
931 num
* sizeof(*ss
->ss_backing
));
932 if ((ss
->ss_flags
& SS_ACTIVE
) == 0)
936 * The stamp reads and writes left -> right only, so we need to
937 * buffer the span if the source and destination regions overlap
938 * and the source is left of the destination.
940 updword
= STAMP_UPDATE_ENABLE
| STAMP_METHOD_COPY
| STAMP_SPAN
;
942 if (src
< dst
&& src
+ num
> dst
)
943 updword
|= STAMP_HALF_BUFF
;
945 row
= (row
* si
->si_fonth
) << 3;
946 num
= (num
* si
->si_fontw
) << 3;
947 src
= row
| ((src
* si
->si_fontw
) << 19);
948 dst
= row
| ((dst
* si
->si_fontw
) << 19);
949 height
= si
->si_fonth
;
951 pbs
= (*si
->si_pbuf_get
)(si
);
954 pb
[0] = STAMP_CMD_COPYSPANS
| STAMP_LW_PERPACKET
;
955 pb
[1] = (height
<< 24) | 0xffffff;
958 pb
[4] = 1; /* linewidth */
960 for ( ; height
!= 0; height
--, src
+= 8, dst
+= 8, pb
+= 3) {
966 (*si
->si_pbuf_post
)(si
, pbs
);
970 stic_putchar(void *cookie
, int r
, int c
, u_int uc
, long attr
)
972 struct wsdisplay_font
*font
;
973 struct stic_screen
*ss
;
974 struct stic_info
*si
;
975 u_int i
, bgcolor
, fgcolor
;
976 u_int
*pb
, v1
, v2
, xya
;
982 /* It's cheaper to use erasecols() to blit blanks. */
984 stic_erasecols(cookie
, r
, c
, 1, attr
);
988 if (ss
->ss_backing
!= NULL
)
989 ss
->ss_backing
[r
* si
->si_consw
+ c
] =
990 (u_short
)((attr
& 0xff) | (uc
<< 8));
991 if ((ss
->ss_flags
& SS_ACTIVE
) == 0)
995 pb
= (*si
->si_pbuf_get
)(si
);
998 * Create a mask from the glyph. Squeeze the foreground color
999 * through the mask, and then squeeze the background color through
1000 * the inverted mask. We may well read outside the glyph when
1001 * creating the mask, but it's bounded by the hardware so it
1002 * shouldn't matter a great deal...
1004 pb
[0] = STAMP_CMD_LINES
| STAMP_RGB_FLAT
| STAMP_XY_PERPRIMATIVE
|
1005 STAMP_LW_PERPRIMATIVE
;
1006 pb
[1] = font
->fontheight
> 16 ? 0x04ffffff : 0x02ffffff;
1008 pb
[3] = STAMP_UPDATE_ENABLE
| STAMP_WE_XYMASK
| STAMP_METHOD_COPY
;
1010 r
*= font
->fontheight
;
1011 c
*= font
->fontwidth
;
1012 uc
= (uc
- font
->firstchar
) * font
->stride
* font
->fontheight
;
1013 fr
= (u_short
*)((char *)font
->data
+ uc
);
1014 bgcolor
= DUPBYTE0((attr
& 0xf0) >> 4);
1015 fgcolor
= DUPBYTE0(attr
& 0x0f);
1017 i
= ((font
->fontheight
> 16 ? 16 : font
->fontheight
) << 2) - 1;
1018 v1
= (c
<< 19) | ((r
<< 3) + i
);
1019 v2
= ((c
+ font
->fontwidth
) << 19) | (v1
& 0xffff);
1020 xya
= XYMASKADDR(si
->si_stampw
, si
->si_stamphm
, c
, r
, 0, 0);
1022 pb
[4] = PACK(fr
, 0);
1023 pb
[5] = PACK(fr
, 2);
1024 pb
[6] = PACK(fr
, 4);
1025 pb
[7] = PACK(fr
, 6);
1026 pb
[8] = PACK(fr
, 8);
1027 pb
[9] = PACK(fr
, 10);
1028 pb
[10] = PACK(fr
, 12);
1029 pb
[11] = PACK(fr
, 14);
1050 /* Two more squeezes for the lower part of the character. */
1051 if (font
->fontheight
> 16) {
1052 i
= ((font
->fontheight
- 16) << 2) - 1;
1054 v1
= (c
<< 19) | ((r
<< 3) + i
);
1055 v2
= ((c
+ font
->fontwidth
) << 19) | (v1
& 0xffff);
1057 pb
[30] = PACK(fr
, 16);
1058 pb
[31] = PACK(fr
, 18);
1059 pb
[32] = PACK(fr
, 20);
1060 pb
[33] = PACK(fr
, 22);
1061 pb
[34] = PACK(fr
, 24);
1062 pb
[35] = PACK(fr
, 26);
1063 pb
[36] = PACK(fr
, 28);
1064 pb
[37] = PACK(fr
, 30);
1086 (*si
->si_pbuf_post
)(si
, pb
);
1090 stic_mapchar(void *cookie
, int c
, u_int
*cp
)
1092 struct stic_info
*si
;
1094 si
= ((struct stic_screen
*)cookie
)->ss_si
;
1096 if (c
< si
->si_font
->firstchar
|| c
== ' ') {
1101 if (c
- si
->si_font
->firstchar
>= si
->si_font
->numchars
) {
1111 stic_cursor(void *cookie
, int on
, int row
, int col
)
1113 struct stic_screen
*ss
;
1114 struct stic_info
*si
;
1120 ss
->ss_curx
= col
* si
->si_fontw
;
1121 ss
->ss_cury
= row
* si
->si_fonth
;
1126 ss
->ss_flags
|= SS_CURENB
;
1128 ss
->ss_flags
&= ~SS_CURENB
;
1130 if ((ss
->ss_flags
& SS_ACTIVE
) != 0) {
1131 si
->si_cursor
.cc_pos
.x
= ss
->ss_curx
;
1132 si
->si_cursor
.cc_pos
.y
= ss
->ss_cury
;
1133 si
->si_flags
|= SI_CURENB_CHANGED
;
1134 stic_set_hwcurpos(si
);
1137 * XXX Since we don't yet receive vblank interrupts from the
1138 * PXG, we must flush immediatley.
1140 if (si
->si_disptype
== WSDISPLAY_TYPE_PXG
)
1148 stic_flush(struct stic_info
*si
)
1150 volatile uint32_t *vdac
;
1153 if ((si
->si_flags
& SI_ALL_CHANGED
) == 0)
1158 si
->si_flags
&= ~SI_ALL_CHANGED
;
1160 if ((v
& SI_CURENB_CHANGED
) != 0) {
1161 SELECT(vdac
, BT459_IREG_CCR
);
1162 if ((si
->si_curscreen
->ss_flags
& SS_CURENB
) != 0)
1163 REG(vdac
, bt_reg
) = 0x00c0c0c0;
1165 REG(vdac
, bt_reg
) = 0x00000000;
1169 if ((v
& SI_CURCMAP_CHANGED
) != 0) {
1172 cp
= si
->si_cursor
.cc_color
;
1174 SELECT(vdac
, BT459_IREG_CCOLOR_2
);
1175 REG(vdac
, bt_reg
) = DUPBYTE0(cp
[1]); tc_wmb();
1176 REG(vdac
, bt_reg
) = DUPBYTE0(cp
[3]); tc_wmb();
1177 REG(vdac
, bt_reg
) = DUPBYTE0(cp
[5]); tc_wmb();
1178 REG(vdac
, bt_reg
) = DUPBYTE0(cp
[0]); tc_wmb();
1179 REG(vdac
, bt_reg
) = DUPBYTE0(cp
[2]); tc_wmb();
1180 REG(vdac
, bt_reg
) = DUPBYTE0(cp
[4]); tc_wmb();
1183 if ((v
& SI_CURSHAPE_CHANGED
) != 0) {
1184 uint8_t *ip
, *mp
, img
, msk
;
1188 ip
= (uint8_t *)si
->si_cursor
.cc_image
;
1189 mp
= (uint8_t *)si
->si_cursor
.cc_mask
;
1192 SELECT(vdac
, BT459_IREG_CRAM_BASE
);
1193 /* 64 pixel scan line is consisted with 16 byte cursor ram */
1194 while (bcnt
< CURSOR_MAX_SIZE
* 16) {
1197 img
&= msk
; /* cookie off image */
1198 u
= (msk
& 0x0f) << 4 | (img
& 0x0f);
1199 REG(vdac
, bt_reg
) = DUPBYTE0(shuffle
[u
]);
1201 u
= (msk
& 0xf0) | (img
& 0xf0) >> 4;
1202 REG(vdac
, bt_reg
) = DUPBYTE0(shuffle
[u
]);
1208 if ((v
& SI_CMAP_CHANGED
) != 0) {
1209 struct stic_hwcmap256
*cm
;
1216 for (index
= 0; index
< CMAP_SIZE
; index
++) {
1217 REG(vdac
, bt_cmap
) = DUPBYTE0(cm
->r
[index
]);
1219 REG(vdac
, bt_cmap
) = DUPBYTE0(cm
->g
[index
]);
1221 REG(vdac
, bt_cmap
) = DUPBYTE0(cm
->b
[index
]);
1228 stic_get_cmap(struct stic_info
*si
, struct wsdisplay_cmap
*p
)
1230 u_int index
= p
->index
, count
= p
->count
;
1233 if (index
>= CMAP_SIZE
|| count
> CMAP_SIZE
- index
)
1236 error
= copyout(&si
->si_cmap
.r
[index
], p
->red
, count
);
1239 error
= copyout(&si
->si_cmap
.g
[index
], p
->green
, count
);
1242 error
= copyout(&si
->si_cmap
.b
[index
], p
->blue
, count
);
1247 stic_set_cmap(struct stic_info
*si
, struct wsdisplay_cmap
*p
)
1249 struct stic_hwcmap256 cmap
;
1256 if (index
>= CMAP_SIZE
|| count
> CMAP_SIZE
- index
)
1259 error
= copyin(p
->red
, &cmap
.r
[index
], count
);
1262 error
= copyin(p
->green
, &cmap
.g
[index
], count
);
1265 error
= copyin(p
->blue
, &cmap
.b
[index
], count
);
1270 memcpy(&si
->si_cmap
.r
[index
], &cmap
.r
[index
], count
);
1271 memcpy(&si
->si_cmap
.g
[index
], &cmap
.g
[index
], count
);
1272 memcpy(&si
->si_cmap
.b
[index
], &cmap
.b
[index
], count
);
1273 si
->si_flags
|= SI_CMAP_CHANGED
;
1277 * XXX Since we don't yet receive vblank interrupts from the PXG, we
1278 * must flush immediatley.
1280 if (si
->si_disptype
== WSDISPLAY_TYPE_PXG
)
1287 stic_set_cursor(struct stic_info
*si
, struct wsdisplay_cursor
*p
)
1289 #define cc (&si->si_cursor)
1290 u_int v
, index
= 0, count
= 0, icount
= 0;
1291 struct stic_screen
*ss
;
1292 uint8_t r
[2], g
[2], b
[2], image
[512], mask
[512];
1296 ss
= si
->si_curscreen
;
1297 if ((v
& WSDISPLAY_CURSOR_DOCMAP
) != 0) {
1298 index
= p
->cmap
.index
;
1299 count
= p
->cmap
.count
;
1300 if (index
>= 2 || (index
+ count
) > 2)
1302 error
= copyin(p
->cmap
.red
, &r
[index
], count
);
1305 error
= copyin(p
->cmap
.green
, &g
[index
], count
);
1308 error
= copyin(p
->cmap
.blue
, &b
[index
], count
);
1312 if ((v
& WSDISPLAY_CURSOR_DOSHAPE
) != 0) {
1313 if (p
->size
.x
> CURSOR_MAX_SIZE
|| p
->size
.y
> CURSOR_MAX_SIZE
)
1315 icount
= ((p
->size
.x
< 33) ? 4 : 8) * p
->size
.y
;
1316 error
= copyin(p
->image
, image
, icount
);
1319 error
= copyin(p
->mask
, mask
, icount
);
1323 if ((v
& (WSDISPLAY_CURSOR_DOPOS
| WSDISPLAY_CURSOR_DOCUR
)) != 0) {
1324 if (v
& WSDISPLAY_CURSOR_DOCUR
)
1325 cc
->cc_hot
= p
->hot
;
1326 if (v
& WSDISPLAY_CURSOR_DOPOS
)
1327 stic_set_curpos(si
, &p
->pos
);
1331 if ((v
& WSDISPLAY_CURSOR_DOCUR
) != 0) {
1333 ss
->ss_flags
|= SS_CURENB
;
1335 ss
->ss_flags
&= ~SS_CURENB
;
1336 si
->si_flags
|= SI_CURENB_CHANGED
;
1338 if ((v
& WSDISPLAY_CURSOR_DOCMAP
) != 0) {
1339 memcpy(&cc
->cc_color
[index
], &r
[index
], count
);
1340 memcpy(&cc
->cc_color
[index
+ 2], &g
[index
], count
);
1341 memcpy(&cc
->cc_color
[index
+ 4], &b
[index
], count
);
1342 si
->si_flags
|= SI_CURCMAP_CHANGED
;
1344 if ((v
& WSDISPLAY_CURSOR_DOSHAPE
) != 0) {
1345 memset(cc
->cc_image
, 0, sizeof cc
->cc_image
);
1346 memcpy(cc
->cc_image
, image
, icount
);
1347 memset(cc
->cc_mask
, 0, sizeof cc
->cc_mask
);
1348 memcpy(cc
->cc_mask
, mask
, icount
);
1349 si
->si_flags
|= SI_CURSHAPE_CHANGED
;
1354 * XXX Since we don't yet receive vblank interrupts from the PXG, we
1355 * must flush immediatley.
1357 if (si
->si_disptype
== WSDISPLAY_TYPE_PXG
)
1365 stic_get_cursor(struct stic_info
*si
, struct wsdisplay_cursor
*p
)
1369 return (EPASSTHROUGH
);
1373 stic_set_curpos(struct stic_info
*si
, struct wsdisplay_curpos
*curpos
)
1389 si
->si_cursor
.cc_pos
.x
= x
;
1390 si
->si_cursor
.cc_pos
.y
= y
;
1391 stic_set_hwcurpos(si
);
1395 stic_set_hwcurpos(struct stic_info
*si
)
1397 volatile uint32_t *vdac
;
1402 x
= si
->si_cursor
.cc_pos
.x
- si
->si_cursor
.cc_hot
.x
;
1403 y
= si
->si_cursor
.cc_pos
.y
- si
->si_cursor
.cc_hot
.y
;
1408 SELECT(vdac
, BT459_IREG_CURSOR_X_LOW
);
1409 REG(vdac
, bt_reg
) = DUPBYTE0(x
); tc_wmb();
1410 REG(vdac
, bt_reg
) = DUPBYTE1(x
); tc_wmb();
1411 REG(vdac
, bt_reg
) = DUPBYTE0(y
); tc_wmb();
1412 REG(vdac
, bt_reg
) = DUPBYTE1(y
); tc_wmb();
1417 * STIC control inteface. We have a separate device for mapping the board,
1418 * because access to the DMA engine means that it's possible to circumvent
1419 * the securelevel mechanism.
1422 sticopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
1424 struct stic_info
*si
;
1427 error
= kauth_authorize_device_passthru(l
->l_cred
, dev
,
1428 KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL
, NULL
);
1431 if (minor(dev
) >= STIC_MAXDV
)
1433 if ((si
= stic_info
[minor(dev
)]) == NULL
)
1437 if ((si
->si_flags
& SI_DVOPEN
) != 0) {
1441 si
->si_flags
|= SI_DVOPEN
;
1448 sticclose(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
1450 struct stic_info
*si
;
1453 si
= stic_info
[minor(dev
)];
1455 si
->si_flags
&= ~SI_DVOPEN
;
1462 sticmmap(dev_t dev
, off_t offset
, int prot
)
1464 struct stic_info
*si
;
1465 struct stic_xmap
*sxm
;
1468 si
= stic_info
[minor(dev
)];
1471 if (si
->si_dispmode
!= WSDISPLAYIO_MODE_MAPPED
)
1475 return ((paddr_t
)-1L);
1477 if (offset
< sizeof(sxm
->sxm_stic
)) {
1478 pa
= STIC_KSEG_TO_PHYS(si
->si_stic
);
1479 return (machine_btop(pa
+ offset
));
1481 offset
-= sizeof(sxm
->sxm_stic
);
1483 if (offset
< sizeof(sxm
->sxm_poll
)) {
1484 pa
= STIC_KSEG_TO_PHYS(si
->si_slotbase
);
1485 return (machine_btop(pa
+ offset
));
1487 offset
-= sizeof(sxm
->sxm_poll
);
1489 if (offset
< si
->si_buf_size
)
1490 return (machine_btop(si
->si_buf_phys
+ offset
));
1492 return ((paddr_t
)-1L);