1 /* $Id: light.c,v 1.5 2007/03/04 06:00:39 christos Exp $ */
4 * Copyright (c) 2006 Stephen M. Rumble
5 * Copyright (c) 2003 Ilpo Ruotsalainen
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
34 * SGI "Light" graphics, a.k.a. "Entry", "Starter", "LG1", and "LG2".
36 * 1024x768 8bpp at 60Hz.
38 * This driver supports the boards found in Indigo R3k and R4k machines.
39 * There is a Crimson variant, but the register offsets differ significantly.
41 * Light's REX chip is the precursor of the REX3 found in "newport", hence
42 * much similarity exists.
45 #include <sys/cdefs.h>
46 __KERNEL_RCSID(0, "$NetBSD: light.c,v 1.4 2006/12/29 05:26:30 rumble Exp $");
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/device.h>
51 #include <sys/malloc.h>
53 #include <machine/sysconf.h>
55 #include <dev/wscons/wsconsio.h>
56 #include <dev/wscons/wsdisplayvar.h>
57 #include <dev/wsfont/wsfont.h>
59 #include <sgimips/gio/giovar.h>
60 #include <sgimips/gio/lightvar.h>
61 #include <sgimips/gio/lightreg.h>
66 struct light_devconfig
*sc_dc
;
69 struct light_devconfig
{
72 bus_space_tag_t dc_st
;
73 bus_space_handle_t dc_sh
;
77 struct wsdisplay_font
*dc_fontdata
;
80 /* always 1024x768x8 */
81 #define LIGHT_XRES 1024
82 #define LIGHT_YRES 768
85 static int light_match(struct device
*, struct cfdata
*, void *);
86 static void light_attach(struct device
*, struct device
*, void *);
88 CFATTACH_DECL(light
, sizeof(struct light_softc
), light_match
, light_attach
,
91 /* wsdisplay_emulops */
92 static void light_cursor(void *, int, int, int);
93 static int light_mapchar(void *, int, unsigned int *);
94 static void light_putchar(void *, int, int, u_int
, long);
95 static void light_copycols(void *, int, int, int, int);
96 static void light_erasecols(void *, int, int, int, long);
97 static void light_copyrows(void *, int, int, int);
98 static void light_eraserows(void *, int, int, long);
99 static int light_allocattr(void *, int, int, int, long *);
101 /* wsdisplay_accessops */
102 static int light_ioctl(void *, void *, u_long
, void *, int, struct lwp
*);
103 static paddr_t
light_mmap(void *, void *, off_t
, int);
104 static int light_alloc_screen(void *, const struct wsscreen_descr
*,
105 void **, int *, int *, long *);
106 static void light_free_screen(void *, void *);
107 static int light_show_screen(void *, void *, int,
108 void (*)(void *, int, int), void *);
110 static const struct wsdisplay_accessops light_accessops
= {
111 .ioctl
= light_ioctl
,
113 .alloc_screen
= light_alloc_screen
,
114 .free_screen
= light_free_screen
,
115 .show_screen
= light_show_screen
,
121 static const struct wsdisplay_emulops light_emulops
= {
122 .cursor
= light_cursor
,
123 .mapchar
= light_mapchar
,
124 .putchar
= light_putchar
,
125 .copycols
= light_copycols
,
126 .erasecols
= light_erasecols
,
127 .copyrows
= light_copyrows
,
128 .eraserows
= light_eraserows
,
129 .allocattr
= light_allocattr
,
133 static const struct wsscreen_descr light_screen
= {
137 .textops
= &light_emulops
,
140 .capabilities
= WSSCREEN_WSCOLORS
| WSSCREEN_HILIT
| WSSCREEN_REVERSE
143 const struct wsscreen_descr
*_light_screenlist
[] = {
147 static const struct wsscreen_list light_screenlist
= {
148 sizeof(_light_screenlist
) / sizeof(_light_screenlist
[0]),
152 static struct light_devconfig light_console_dc
;
153 static int light_is_console
= 0;
155 #define LIGHT_ATTR_ENCODE(fg, bg) (((fg << 8) & 0xff00) | (bg * 0x00ff))
156 #define LIGHT_ATTR_FG(attr) ((attr >> 8) & 0x00ff)
157 #define LIGHT_ATTR_BG(attr) (attr & 0x00ff)
159 #define LIGHT_IS_LG1(_rev) ((_rev) < 2) /* else LG2 */
161 /*******************************************************************************
162 * REX routines and helper functions
163 ******************************************************************************/
166 rex_read(struct light_devconfig
*dc
, uint32_t rset
, uint32_t r
)
169 return (bus_space_read_4(dc
->dc_st
, dc
->dc_sh
, rset
+ r
));
173 rex_write(struct light_devconfig
*dc
, uint32_t rset
, uint32_t r
, uint32_t v
)
176 bus_space_write_4(dc
->dc_st
, dc
->dc_sh
, rset
+ r
, v
);
180 rex_vc1_read(struct light_devconfig
*dc
)
183 rex_write(dc
, REX_PAGE1_GO
, REX_P1REG_CFGSEL
, REX_CFGSEL_VC1_SYSCTL
);
184 rex_read(dc
, REX_PAGE1_GO
, REX_P1REG_VC1_ADDRDATA
);
185 return (rex_read(dc
, REX_PAGE1_SET
, REX_P1REG_VC1_ADDRDATA
));
189 rex_vc1_write(struct light_devconfig
*dc
, uint8_t val
)
192 rex_write(dc
, REX_PAGE1_GO
, REX_P1REG_CFGSEL
, REX_CFGSEL_VC1_SYSCTL
);
193 rex_write(dc
, REX_PAGE1_SET
, REX_P1REG_VC1_ADDRDATA
, val
);
194 rex_write(dc
, REX_PAGE1_GO
, REX_P1REG_VC1_ADDRDATA
, val
);
198 rex_wait(struct light_devconfig
*dc
)
201 while (rex_read(dc
, REX_PAGE1_SET
,REX_P1REG_CFGMODE
) & REX_CFGMODE_BUSY
)
206 rex_revision(struct light_devconfig
*dc
)
209 rex_write(dc
, REX_PAGE1_SET
, REX_P1REG_CFGSEL
, REX_CFGSEL_VC1_LADDR
);
210 rex_read(dc
, REX_PAGE1_GO
, REX_P1REG_WCLOCKREV
);
211 return (rex_read(dc
, REX_PAGE1_SET
, REX_P1REG_WCLOCKREV
) & 0x7);
215 rex_copy_rect(struct light_devconfig
*dc
, int from_x
, int from_y
, int to_x
,
216 int to_y
, int width
, int height
)
218 int dx
, dy
, ystarti
, yendi
;
223 /* adjust for y. NB: STOPONX, STOPONY are inclusive */
225 ystarti
= to_y
+ height
- 1;
229 yendi
= to_y
+ height
- 1;
234 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_XSTARTI
, to_x
);
235 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_XENDI
, to_x
+ width
);
236 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_YSTARTI
, ystarti
);
237 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_YENDI
, yendi
);
238 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_COMMAND
, REX_OP_DRAW
|
239 REX_LOGICOP_SRC
| REX_OP_FLG_LOGICSRC
| REX_OP_FLG_QUADMODE
|
240 REX_OP_FLG_BLOCK
| REX_OP_FLG_STOPONX
| REX_OP_FLG_STOPONY
);
241 rex_write(dc
, REX_PAGE0_GO
, REX_P0REG_XYMOVE
,
242 ((dx
<< 16) & 0xffff0000) | (dy
& 0x0000ffff));
246 rex_fill_rect(struct light_devconfig
*dc
, int from_x
, int from_y
, int to_x
,
252 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_YSTARTI
, from_y
);
253 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_YENDI
, to_y
);
254 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_XSTARTI
, from_x
);
255 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_XENDI
, to_x
);
256 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_COLORREDI
, LIGHT_ATTR_BG(attr
));
257 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_COMMAND
, REX_OP_DRAW
|
258 REX_LOGICOP_SRC
| REX_OP_FLG_QUADMODE
| REX_OP_FLG_BLOCK
|
259 REX_OP_FLG_STOPONX
| REX_OP_FLG_STOPONY
);
260 rex_read(dc
, REX_PAGE0_GO
, REX_P0REG_COMMAND
);
263 /*******************************************************************************
264 * match/attach functions
265 ******************************************************************************/
268 light_match(struct device
*parent
, struct cfdata
*self
, void *aux
)
270 struct gio_attach_args
*ga
= aux
;
272 if (ga
->ga_addr
!= LIGHT_ADDR_0
&& ga
->ga_addr
!= LIGHT_ADDR_1
)
275 if (platform
.badaddr(
276 (void *)(ga
->ga_ioh
+ REX_PAGE1_SET
+ REX_P1REG_XYOFFSET
),
280 if (bus_space_read_4(ga
->ga_iot
, ga
->ga_ioh
,
281 REX_PAGE1_SET
+ REX_P1REG_XYOFFSET
) != 0x08000800)
288 light_attach_common(struct light_devconfig
*dc
, struct gio_attach_args
*ga
)
291 dc
->dc_addr
= ga
->ga_addr
;
292 dc
->dc_st
= ga
->ga_iot
;
293 dc
->dc_sh
= ga
->ga_ioh
;
295 dc
->dc_boardrev
= rex_revision(dc
);
299 dc
->dc_font
= wsfont_find(NULL
, 8, 16, 0, WSDISPLAY_FONTORDER_L2R
,
300 WSDISPLAY_FONTORDER_L2R
);
303 panic("light_attach_common: no suitable fonts");
305 if (wsfont_lock(dc
->dc_font
, &dc
->dc_fontdata
))
306 panic("light_attach_common: unable to lock font data");
308 rex_vc1_write(dc
, rex_vc1_read(dc
) & ~(VC1_SYSCTL_CURSOR
|
309 VC1_SYSCTL_CURSOR_ON
));
310 rex_fill_rect(dc
, 0, 0, LIGHT_XRES
- 1, LIGHT_YRES
- 1, 0);
314 light_attach(struct device
*parent
, struct device
*self
, void *aux
)
316 struct gio_attach_args
*ga
= aux
;
317 struct light_softc
*sc
= (void *)self
;
318 struct wsemuldisplaydev_attach_args wa
;
320 if (light_is_console
&& ga
->ga_addr
== light_console_dc
.dc_addr
) {
322 sc
->sc_dc
= &light_console_dc
;
325 sc
->sc_dc
= malloc(sizeof(struct light_devconfig
), M_DEVBUF
,
327 if (sc
->sc_dc
== NULL
)
328 panic("light_attach: out of memory");
330 light_attach_common(sc
->sc_dc
, ga
);
333 aprint_naive(": Display adapter\n");
335 aprint_normal(": SGI LG%d (board revision %d)\n",
336 LIGHT_IS_LG1(sc
->sc_dc
->dc_boardrev
) ? 1 : 2,
337 sc
->sc_dc
->dc_boardrev
);
339 wa
.scrdata
= &light_screenlist
;
340 wa
.accessops
= &light_accessops
;
341 wa
.accesscookie
= sc
->sc_dc
;
343 config_found(&sc
->sc_dev
, &wa
, wsemuldisplaydevprint
);
347 light_cnattach(struct gio_attach_args
*ga
)
350 if (!light_match(NULL
, NULL
, ga
))
353 light_attach_common(&light_console_dc
, ga
);
355 wsdisplay_cnattach(&light_screen
, &light_console_dc
, 0, 0,
356 LIGHT_ATTR_ENCODE(WSCOL_WHITE
, WSCOL_BLACK
));
358 light_is_console
= 1;
363 /*******************************************************************************
365 ******************************************************************************/
368 light_cursor(void *c
, int on
, int row
, int col
)
374 light_mapchar(void *c
, int ch
, unsigned int *cp
)
376 struct light_devconfig
*dc
= (void *)c
;
378 if (dc
->dc_fontdata
->encoding
!= WSDISPLAY_FONTENC_ISO
) {
379 ch
= wsfont_map_unichar(dc
->dc_fontdata
, ch
);
385 if (ch
< dc
->dc_fontdata
->firstchar
||
386 ch
>= dc
->dc_fontdata
->firstchar
+ dc
->dc_fontdata
->numchars
)
398 light_putchar(void *c
, int row
, int col
, u_int ch
, long attr
)
400 struct light_devconfig
*dc
= c
;
401 struct wsdisplay_font
*font
= dc
->dc_fontdata
;
406 bitmap
= (u_int8_t
*)font
->data
+
407 ((ch
- font
->firstchar
) * font
->fontheight
* font
->stride
);
408 x
= col
* font
->fontwidth
;
409 y
= row
* font
->fontheight
;
413 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_YSTARTI
, y
);
414 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_YENDI
, y
+ font
->fontheight
- 1);
415 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_XSTARTI
, x
);
416 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_XENDI
, x
+ font
->fontwidth
- 1);
417 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_COLORREDI
, LIGHT_ATTR_FG(attr
));
418 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_COLORBACK
, LIGHT_ATTR_BG(attr
));
419 rex_write(dc
, REX_PAGE0_GO
, REX_P0REG_COMMAND
, REX_OP_NOP
);
423 rex_write(dc
, REX_PAGE0_SET
, REX_P0REG_COMMAND
, REX_OP_DRAW
|
424 REX_LOGICOP_SRC
| REX_OP_FLG_ENZPATTERN
| REX_OP_FLG_QUADMODE
|
425 REX_OP_FLG_XYCONTINUE
| REX_OP_FLG_STOPONX
| REX_OP_FLG_BLOCK
|
426 REX_OP_FLG_LENGTH32
| REX_OP_FLG_ZOPAQUE
);
428 for (i
= 0; i
< font
->fontheight
; i
++) {
429 /* XXX assumes font->fontwidth == 8 */
430 pattern
= *bitmap
<< 24;
431 rex_write(dc
, REX_PAGE0_GO
, REX_P0REG_ZPATTERN
, pattern
);
432 bitmap
+= font
->stride
;
436 /* copy set of columns within the same line */
438 light_copycols(void *c
, int row
, int srccol
, int dstcol
, int ncols
)
440 struct light_devconfig
*dc
= c
;
441 struct wsdisplay_font
*font
= dc
->dc_fontdata
;
442 int from_x
, from_y
, to_x
, to_y
, width
, height
;
444 from_x
= srccol
* font
->fontwidth
;
445 from_y
= row
* font
->fontheight
;
446 to_x
= dstcol
* font
->fontwidth
;
448 width
= ncols
* font
->fontwidth
;
449 height
= font
->fontheight
;
451 rex_copy_rect(c
, from_x
, from_y
, to_x
, to_y
, width
, height
);
454 /* erase a set of columns in the same line */
456 light_erasecols(void *c
, int row
, int startcol
, int ncols
, long attr
)
458 struct light_devconfig
*dc
= c
;
459 struct wsdisplay_font
*font
= dc
->dc_fontdata
;
460 int from_x
, from_y
, to_x
, to_y
;
462 from_x
= startcol
* font
->fontwidth
;
463 from_y
= row
* font
->fontheight
;
464 to_x
= from_x
+ (ncols
* font
->fontwidth
) - 1;
465 to_y
= from_y
+ font
->fontheight
- 1;
467 rex_fill_rect(c
, from_x
, from_y
, to_x
, to_y
, attr
);
470 /* copy a set of complete rows */
472 light_copyrows(void *c
, int srcrow
, int dstrow
, int nrows
)
474 struct light_devconfig
*dc
= c
;
475 struct wsdisplay_font
*font
= dc
->dc_fontdata
;
476 int from_x
, from_y
, to_x
, to_y
, width
, height
;
479 from_y
= srcrow
* font
->fontheight
;
481 to_y
= dstrow
* font
->fontheight
;
483 height
= nrows
* font
->fontheight
;
485 rex_copy_rect(c
, from_x
, from_y
, to_x
, to_y
, width
, height
);
488 /* erase a set of complete rows */
490 light_eraserows(void *c
, int row
, int nrows
, long attr
)
492 struct light_devconfig
*dc
= c
;
493 struct wsdisplay_font
*font
= dc
->dc_fontdata
;
494 int from_x
, from_y
, to_x
, to_y
;
497 from_y
= row
* font
->fontheight
;
498 to_x
= LIGHT_XRES
- 1;
499 to_y
= from_y
+ (nrows
* font
->fontheight
) - 1;
501 rex_fill_rect(c
, from_x
, from_y
, to_x
, to_y
, attr
);
505 light_allocattr(void *c
, int fg
, int bg
, int flags
, long *attr
)
508 if (flags
& ~(WSATTR_WSCOLORS
| WSATTR_HILIT
| WSATTR_REVERSE
))
511 if ((flags
& WSATTR_WSCOLORS
) == 0) {
516 if (flags
& WSATTR_HILIT
)
519 if (flags
& WSATTR_REVERSE
) {
525 *attr
= LIGHT_ATTR_ENCODE(fg
, bg
);
529 /*******************************************************************************
530 * wsdisplay_accessops
531 ******************************************************************************/
534 light_ioctl(void *c
, void *vs
, u_long cmd
, void *data
, int flag
,
537 struct wsdisplay_fbinfo
*fbinfo
= (struct wsdisplay_fbinfo
*)data
;
540 case WSDISPLAYIO_GINFO
:
541 fbinfo
->width
= LIGHT_XRES
;
542 fbinfo
->height
= LIGHT_YRES
;
543 fbinfo
->depth
= LIGHT_DEPTH
;
544 fbinfo
->cmsize
= 1 << LIGHT_DEPTH
;
547 case WSDISPLAYIO_GMODE
:
548 *(u_int
*)data
= WSDISPLAYIO_MODE_EMUL
;
551 case WSDISPLAYIO_GTYPE
:
552 *(u_int
*)data
= WSDISPLAY_TYPE_LIGHT
;
555 case WSDISPLAYIO_SVIDEO
:
557 * Turning off VC1 will stop refreshing the video ram (or so I
558 * suspect). We'll blank the screen after bringing it back up,
559 * since that's nicer than displaying garbage.
561 if (*(u_int
*)data
== WSDISPLAYIO_VIDEO_OFF
)
562 rex_vc1_write(c
,rex_vc1_read(c
) & ~VC1_SYSCTL_VIDEO_ON
);
564 rex_vc1_write(c
, rex_vc1_read(c
) | VC1_SYSCTL_VIDEO_ON
);
565 rex_fill_rect(c
, 0, 0, LIGHT_XRES
-1, LIGHT_YRES
-1, 0);
570 return (EPASSTHROUGH
);
574 light_mmap(void *c
, void *vs
, off_t off
, int prot
)
576 struct light_devconfig
*dc
= c
;
581 return (mips_btop(dc
->dc_addr
+ off
));
585 light_alloc_screen(void *c
, const struct wsscreen_descr
*type
, void **cookiep
,
586 int *curxp
, int *curyp
, long *attr
)
593 light_free_screen(void *c
, void *cookie
)
596 panic("light_free_screen");
600 light_show_screen(void *c
, void *cookie
, int waitok
,
601 void (*cb
)(void *, int, int), void *cbarg
)