1 /* $NetBSD: pm.c,v 1.6 2008/04/28 20:23:31 martin Exp $ */
4 * Copyright (c) 2002, 2003 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.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: pm.c,v 1.6 2008/04/28 20:23:31 martin Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
40 #include <sys/ioctl.h>
42 #include <machine/bus.h>
43 #include <machine/intr.h>
45 #include <dev/wscons/wsconsio.h>
46 #include <dev/wscons/wsdisplayvar.h>
47 #include <dev/rasops/rasops.h>
48 #include <dev/wsfont/wsfont.h>
50 #include <pmax/pmax/kn01.h>
52 #include <pmax/ibus/ibusvar.h>
53 #include <pmax/ibus/pmreg.h>
55 #include <uvm/uvm_extern.h>
57 #define CURSOR_MAX_SIZE 16
66 struct wsdisplay_curpos cc_pos
;
67 struct wsdisplay_curpos cc_hot
;
68 struct wsdisplay_curpos cc_size
;
72 * Max cursor size is 16x16. The X server pads bitmap scanlines to
73 * a word boundary. We take the easy route and waste some space.
75 u_short cc_image
[32 + 32];
87 struct hwcursor64 sc_cursor
;
88 struct hwcmap256 sc_cmap
;
90 #define WSDISPLAY_CMAP_DOLUT 0x20
92 int pm_match(struct device
*, struct cfdata
*, void *);
93 void pm_attach(struct device
*, struct device
*, void *);
94 int pm_ioctl(void *, void *, u_long
, void *, int, struct lwp
*);
95 paddr_t
pm_mmap(void *, void *, off_t
, int);
96 int pm_alloc_screen(void *, const struct wsscreen_descr
*,
97 void **, int *, int *, long *);
98 void pm_free_screen(void *, void *);
99 int pm_show_screen(void *, void *, int,
100 void (*) (void *, int, int), void *);
101 void pm_cursor_off(void);
102 void pm_cursor_on(struct pm_softc
*);
103 int pm_cnattach(void);
104 void pm_common_init(void);
105 int pm_flush(struct pm_softc
*);
106 int pm_get_cmap(struct pm_softc
*, struct wsdisplay_cmap
*);
107 int pm_set_cmap(struct pm_softc
*, struct wsdisplay_cmap
*);
108 int pm_set_cursor(struct pm_softc
*, struct wsdisplay_cursor
*);
109 int pm_get_cursor(struct pm_softc
*, struct wsdisplay_cursor
*);
110 void pm_set_curpos(struct pm_softc
*, struct wsdisplay_curpos
*);
111 void pm_init_cmap(struct pm_softc
*);
113 CFATTACH_DECL(pm
, sizeof(struct pm_softc
),
114 pm_match
, pm_attach
, NULL
, NULL
);
116 struct rasops_info pm_ri
;
118 struct wsscreen_descr pm_stdscreen
= {
125 const struct wsscreen_descr
*_pm_scrlist
[] = {
129 const struct wsscreen_list pm_screenlist
= {
130 sizeof(_pm_scrlist
) / sizeof(struct wsscreen_descr
*), _pm_scrlist
133 const struct wsdisplay_accessops pm_accessops
= {
145 pm_match(struct device
*parent
, struct cfdata
*match
, void *aux
)
147 struct ibus_attach_args
*ia
;
151 pmaddr
= (void *)ia
->ia_addr
;
153 if (strcmp(ia
->ia_name
, "pm") != 0)
156 if (badaddr(pmaddr
, 4))
163 pm_attach(struct device
*parent
, struct device
*self
, void *aux
)
166 struct rasops_info
*ri
;
167 struct wsemuldisplaydev_attach_args waa
;
170 sc
= (struct pm_softc
*)self
;
172 console
= (ri
->ri_bits
!= NULL
);
179 printf(": %dx%d, %dbpp\n", ri
->ri_width
, ri
->ri_height
, ri
->ri_depth
);
186 waa
.console
= console
;
187 waa
.scrdata
= &pm_screenlist
;
188 waa
.accessops
= &pm_accessops
;
189 waa
.accesscookie
= sc
;
191 config_found(self
, &waa
, wsemuldisplaydevprint
);
195 pm_init_cmap(struct pm_softc
*sc
)
197 struct hwcmap256
*cm
;
198 struct rasops_info
*ri
;
205 if (ri
->ri_depth
== 8) {
207 for (index
= 0; index
< 256; index
++, p
+= 3) {
213 sc
->sc_type
= WSDISPLAY_TYPE_PM_COLOR
;
214 sc
->sc_cmap_size
= 256;
215 sc
->sc_fb_size
= 0x100000;
225 sc
->sc_type
= WSDISPLAY_TYPE_PM_MONO
;
226 sc
->sc_cmap_size
= 2;
227 sc
->sc_fb_size
= 0x40000;
234 struct rasops_info
*ri
;
240 kn01csr
= *(volatile uint16_t *)MIPS_PHYS_TO_KSEG1(KN01_SYS_CSR
);
241 pcc
= (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC
);
242 vdac
= (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_VDAC
);
245 ri
->ri_flg
= RI_CENTER
;
246 ri
->ri_depth
= ((kn01csr
& KN01_CSR_MONO
) != 0 ? 1 : 8);
249 ri
->ri_stride
= (ri
->ri_depth
== 8 ? 1024 : 2048 / 8);
250 ri
->ri_bits
= (void *)MIPS_PHYS_TO_KSEG1(KN01_PHYS_FBUF_START
);
255 memset(ri
->ri_bits
, 0, ri
->ri_stride
* ri
->ri_height
);
260 bior
= (ri
->ri_depth
== 8 ? WSDISPLAY_FONTORDER_L2R
:
261 WSDISPLAY_FONTORDER_R2L
);
264 if (ri
->ri_depth
== 8)
265 cookie
= wsfont_find(NULL
, 12, 0, 0, bior
,
266 WSDISPLAY_FONTORDER_L2R
);
268 cookie
= wsfont_find(NULL
, 8, 0, 0, bior
,
269 WSDISPLAY_FONTORDER_L2R
);
271 cookie
= wsfont_find(NULL
, 0, 0, 0, bior
,
272 WSDISPLAY_FONTORDER_L2R
);
274 printf("pm: font table is empty\n");
278 if (wsfont_lock(cookie
, &ri
->ri_font
)) {
279 printf("pm: couldn't lock font\n");
282 ri
->ri_wsfcookie
= cookie
;
285 * Set up the raster operations set.
287 rasops_init(ri
, 1000, 1000);
289 pm_stdscreen
.nrows
= ri
->ri_rows
;
290 pm_stdscreen
.ncols
= ri
->ri_cols
;
291 pm_stdscreen
.textops
= &ri
->ri_ops
;
292 pm_stdscreen
.capabilities
= ri
->ri_caps
;
295 * Initalize the VDAC.
297 *(uint8_t *)MIPS_PHYS_TO_KSEG1(KN01_PHYS_COLMASK_START
) = 0xff;
300 vdac
->overWA
= 0x04; wbflush();
301 vdac
->over
= 0x00; wbflush();
302 vdac
->over
= 0x00; wbflush();
303 vdac
->over
= 0x00; wbflush();
304 vdac
->overWA
= 0x08; wbflush();
305 vdac
->over
= 0x00; wbflush();
306 vdac
->over
= 0x00; wbflush();
307 vdac
->over
= 0x7f; wbflush();
308 vdac
->overWA
= 0x0c; wbflush();
309 vdac
->over
= 0xff; wbflush();
310 vdac
->over
= 0xff; wbflush();
311 vdac
->over
= 0xff; wbflush();
314 * Set in the initial colormap.
316 if (ri
->ri_depth
== 8) {
320 for (i
= 0; i
< 256 * 3; i
+= 3) {
321 vdac
->map
= rasops_cmap
[i
];
323 vdac
->map
= rasops_cmap
[i
+ 1];
325 vdac
->map
= rasops_cmap
[i
+ 2];
332 for (i
= 0; i
< 256; i
++) {
335 vdac
->map
= (i
< 128 ? 0x00 : 0xff);
343 * Turn off the hardware cursor sprite for text mode.
345 pcc
->cmdr
= PCC_FOPB
| PCC_VBHI
;
356 pcc
= (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC
);
357 pcc
->cmdr
= (pm_creg
&= ~(PCC_ENPA
| PCC_ENPB
));
362 pm_cursor_on(struct pm_softc
*sc
)
367 pcc
= (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC
);
368 pcc
->cmdr
= (pm_creg
|= (PCC_ENPA
| PCC_ENPB
));
374 pm_ioctl(void *v
, void *vs
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
377 struct rasops_info
*ri
;
385 pcc
= (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC
);
386 vdac
= (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_VDAC
);
389 case WSDISPLAYIO_GTYPE
:
390 *(u_int
*)data
= sc
->sc_type
;
393 case WSDISPLAYIO_SMODE
:
394 if (*(u_int
*)data
== WSDISPLAYIO_MODE_EMUL
) {
397 memset(ri
->ri_bits
, 0, ri
->ri_stride
* ri
->ri_height
);
399 sc
->sc_changed
|= WSDISPLAY_CMAP_DOLUT
;
403 case WSDISPLAYIO_GINFO
:
404 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
405 wsd_fbip
->height
= ri
->ri_height
;
406 wsd_fbip
->width
= ri
->ri_width
;
407 wsd_fbip
->depth
= ri
->ri_depth
;
408 wsd_fbip
->cmsize
= sc
->sc_cmap_size
;
412 case WSDISPLAYIO_GETCMAP
:
413 rv
= pm_get_cmap(sc
, (struct wsdisplay_cmap
*)data
);
416 case WSDISPLAYIO_PUTCMAP
:
417 rv
= pm_set_cmap(sc
, (struct wsdisplay_cmap
*)data
);
420 case WSDISPLAYIO_SVIDEO
:
421 turnoff
= (*(int *)data
== WSDISPLAYIO_VIDEO_OFF
);
422 if ((sc
->sc_blanked
== 0) ^ turnoff
) {
423 sc
->sc_blanked
= turnoff
;
426 (pm_creg
&= ~(PCC_FOPA
| PCC_FOPB
));
429 sc
->sc_changed
|= WSDISPLAY_CURSOR_DOCMAP
;
433 (pm_creg
|= (PCC_FOPA
| PCC_FOPB
));
437 for (i
= 0; i
< 3; i
++) {
445 case WSDISPLAYIO_GVIDEO
:
446 *(u_int
*)data
= (sc
->sc_blanked
?
447 WSDISPLAYIO_VIDEO_OFF
: WSDISPLAYIO_VIDEO_ON
);
450 case WSDISPLAYIO_GCURPOS
:
451 *(struct wsdisplay_curpos
*)data
= sc
->sc_cursor
.cc_pos
;
454 case WSDISPLAYIO_SCURPOS
:
455 pm_set_curpos(sc
, (struct wsdisplay_curpos
*)data
);
456 sc
->sc_changed
|= WSDISPLAY_CURSOR_DOPOS
;
459 case WSDISPLAYIO_GCURMAX
:
460 ((struct wsdisplay_curpos
*)data
)->x
=
461 ((struct wsdisplay_curpos
*)data
)->y
= CURSOR_MAX_SIZE
;
464 case WSDISPLAYIO_GCURSOR
:
465 rv
= pm_get_cursor(sc
, (struct wsdisplay_cursor
*)data
);
468 case WSDISPLAYIO_SCURSOR
:
469 rv
= pm_set_cursor(sc
, (struct wsdisplay_cursor
*)data
);
482 pm_mmap(void *v
, void *vs
, off_t offset
, int prot
)
488 if (offset
>= sc
->sc_fb_size
|| offset
< 0)
491 return (mips_btop(KN01_PHYS_FBUF_START
+ offset
));
495 pm_alloc_screen(void *v
, const struct wsscreen_descr
*type
, void **cookiep
,
496 int *curxp
, int *curyp
, long *attrp
)
499 struct rasops_info
*ri
;
505 if (sc
->sc_nscreens
> 0)
508 *cookiep
= ri
; /* one and only for now */
511 (*ri
->ri_ops
.allocattr
)(ri
, 0, 0, 0, &defattr
);
518 pm_free_screen(void *v
, void *cookie
)
521 panic("pm_free_screen: console");
525 pm_show_screen(void *v
, void *cookie
, int waitok
,
526 void (*cb
)(void *, int, int), void *cbarg
)
535 struct rasops_info
*ri
;
541 (*ri
->ri_ops
.allocattr
)(ri
, 0, 0, 0, &defattr
);
542 wsdisplay_cnattach(&pm_stdscreen
, ri
, 0, 0, defattr
);
547 pm_flush(struct pm_softc
*sc
)
554 struct hwcmap256
*cm
;
555 struct rasops_info
*ri
;
557 if (sc
->sc_changed
== 0)
560 vdac
= (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_VDAC
);
561 pcc
= (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC
);
565 if ((v
& WSDISPLAY_CURSOR_DOCUR
) != 0) {
572 if ((v
& (WSDISPLAY_CURSOR_DOPOS
| WSDISPLAY_CURSOR_DOHOT
)) != 0) {
573 x
= sc
->sc_cursor
.cc_pos
.x
- sc
->sc_cursor
.cc_hot
.x
;
574 y
= sc
->sc_cursor
.cc_pos
.y
- sc
->sc_cursor
.cc_hot
.y
;
575 pcc
->xpos
= x
+ PCC_X_OFFSET
;
576 pcc
->ypos
= y
+ PCC_Y_OFFSET
;
579 if ((v
& WSDISPLAY_CURSOR_DOCMAP
) != 0) {
580 cp
= sc
->sc_cursor
.cc_color
;
584 for (i
= 1; i
< 6; i
+= 2) {
600 for (i
= 0; i
< 6; i
+= 2) {
605 if ((v
& WSDISPLAY_CURSOR_DOSHAPE
) != 0) {
606 pcc
->cmdr
= (pm_creg
| PCC_LODSA
);
609 p
= sc
->sc_cursor
.cc_image
;
610 x
= 0xffff >> (16 - sc
->sc_cursor
.cc_size
.x
);
611 for (pe
= p
+ 64; p
< pe
; p
+= 2) {
612 pcc
->memory
= *p
& x
;
616 pcc
->cmdr
= (pm_creg
&= ~PCC_LODSA
);
620 if ((v
& WSDISPLAY_CMAP_DOLUT
) != 0) {
626 if (sc
->sc_cmap_size
== 2) {
627 for (i
= 0; i
< 128; i
++) {
630 vdac
->map
= cm
->g
[0];
635 for (; i
< 256; i
++) {
638 vdac
->map
= cm
->g
[1];
644 for (i
= 0; i
< sc
->sc_cmap_size
; i
++) {
645 vdac
->map
= cm
->r
[i
];
647 vdac
->map
= cm
->g
[i
];
649 vdac
->map
= cm
->b
[i
];
660 pm_get_cmap(struct pm_softc
*sc
, struct wsdisplay_cmap
*p
)
668 if (index
>= sc
->sc_cmap_size
|| (index
+ count
) > sc
->sc_cmap_size
)
671 if ((rv
= copyout(&sc
->sc_cmap
.r
[index
], p
->red
, count
)) != 0)
673 if ((rv
= copyout(&sc
->sc_cmap
.g
[index
], p
->green
, count
)) != 0)
675 return (copyout(&sc
->sc_cmap
.b
[index
], p
->blue
, count
));
679 pm_set_cmap(struct pm_softc
*sc
, struct wsdisplay_cmap
*p
)
687 if (index
>= sc
->sc_cmap_size
|| (index
+ count
) > sc
->sc_cmap_size
)
690 if ((rv
= copyin(p
->red
, &sc
->sc_cmap
.r
[index
], count
)) != 0)
692 if ((rv
= copyin(p
->green
, &sc
->sc_cmap
.g
[index
], count
)) != 0)
694 if ((rv
= copyin(p
->blue
, &sc
->sc_cmap
.b
[index
], count
)) != 0)
696 sc
->sc_changed
|= WSDISPLAY_CMAP_DOLUT
;
701 pm_set_cursor(struct pm_softc
*sc
, struct wsdisplay_cursor
*p
)
703 u_int v
, index
, count
;
704 struct hwcursor64
*cc
;
710 if ((v
& WSDISPLAY_CURSOR_DOCUR
) != 0)
711 sc
->sc_curenb
= p
->enable
;
712 if ((v
& WSDISPLAY_CURSOR_DOPOS
) != 0)
713 pm_set_curpos(sc
, &p
->pos
);
714 if ((v
& WSDISPLAY_CURSOR_DOHOT
) != 0)
716 if ((v
& WSDISPLAY_CURSOR_DOCMAP
) != 0) {
717 index
= p
->cmap
.index
;
718 count
= p
->cmap
.count
;
719 if (index
>= 2 || (index
+ count
) > 2)
722 rv
= copyin(p
->cmap
.red
, &cc
->cc_color
[index
], count
);
725 rv
= copyin(p
->cmap
.green
, &cc
->cc_color
[index
+ 2], count
);
728 rv
= copyin(p
->cmap
.blue
, &cc
->cc_color
[index
+ 4], count
);
732 if ((v
& WSDISPLAY_CURSOR_DOSHAPE
) != 0) {
733 if (p
->size
.x
> CURSOR_MAX_SIZE
||
734 p
->size
.y
> CURSOR_MAX_SIZE
)
737 cc
->cc_size
= p
->size
;
738 memset(cc
->cc_image
, 0, sizeof(cc
->cc_image
));
739 rv
= copyin(p
->image
, cc
->cc_image
, p
->size
.y
* 4);
742 rv
= copyin(p
->mask
, cc
->cc_image
+32, p
->size
.y
* 4);
752 pm_get_cursor(struct pm_softc
*sc
, struct wsdisplay_cursor
*p
)
755 return (ENOTTY
); /* XXX */
759 pm_set_curpos(struct pm_softc
*sc
, struct wsdisplay_curpos
*curpos
)
761 struct rasops_info
*ri
;
770 else if (y
> ri
->ri_height
)
774 else if (x
> ri
->ri_width
)
776 sc
->sc_cursor
.cc_pos
.x
= x
;
777 sc
->sc_cursor
.cc_pos
.y
= y
;