1 /* $NetBSD: ofb.c,v 1.63 2007/11/26 19:58:29 garbled Exp $ */
4 * Copyright (c) 1995, 1996 Carnegie-Mellon University.
7 * Author: Chris G. Demetriou
9 * Permission to use, copy, modify and distribute this software and
10 * its documentation is hereby granted, provided that both the copyright
11 * notice and this permission notice appear in all copies of the
12 * software, derivative works or modified versions, and any portions
13 * thereof, and that both notices appear in supporting documentation.
15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19 * Carnegie Mellon requests users of this software to return to
21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
22 * School of Computer Science
23 * Carnegie Mellon University
24 * Pittsburgh PA 15213-3890
26 * any improvements or extensions that they make and grant Carnegie the
27 * rights to redistribute these changes.
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: ofb.c,v 1.63 2007/11/26 19:58:29 garbled Exp $");
33 #include <sys/param.h>
36 #include <sys/device.h>
37 #include <sys/ioctl.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/systm.h>
41 #include <sys/kauth.h>
44 #include <uvm/uvm_extern.h>
46 #include <dev/pci/pcidevs.h>
47 #include <dev/pci/pcireg.h>
48 #include <dev/pci/pcivar.h>
49 #include <dev/pci/pciio.h>
51 #include <dev/wscons/wsconsio.h>
52 #include <dev/wscons/wsdisplayvar.h>
53 #include <dev/rasops/rasops.h>
54 #include <dev/wsfont/wsfont.h>
56 #include <dev/ofw/openfirm.h>
57 #include <dev/ofw/ofw_pci.h>
59 #include <machine/bus.h>
60 #include <machine/autoconf.h>
61 #include <machine/grfioctl.h>
63 #include <dev/wscons/wsdisplay_vconsvar.h>
65 #include <powerpc/oea/ofw_rasconsvar.h>
70 pci_chipset_tag_t sc_pc
;
72 bus_space_tag_t sc_memt
;
73 bus_space_tag_t sc_iot
;
75 u_int32_t sc_addrs
[30]; /* "assigned-addresses" storage */
76 u_char sc_cmap_red
[256];
77 u_char sc_cmap_green
[256];
78 u_char sc_cmap_blue
[256];
80 int sc_node
, sc_ih
, sc_mode
;
87 static int ofbmatch(struct device
*, struct cfdata
*, void *);
88 static void ofbattach(struct device
*, struct device
*, void *);
90 CFATTACH_DECL(ofb
, sizeof(struct ofb_softc
),
91 ofbmatch
, ofbattach
, NULL
, NULL
);
93 const struct wsscreen_descr
*_ofb_scrlist
[] = {
95 /* XXX other formats, graphics screen? */
98 struct wsscreen_list ofb_screenlist
= {
99 sizeof(_ofb_scrlist
) / sizeof(struct wsscreen_descr
*), _ofb_scrlist
102 static int ofb_ioctl(void *, void *, u_long
, void *, int, struct lwp
*);
103 static paddr_t
ofb_mmap(void *, void *, off_t
, int);
105 static void ofb_init_screen(void *, struct vcons_screen
*, int, long *);
107 struct wsdisplay_accessops ofb_accessops
= {
110 NULL
, /* vcons_alloc_screen */
111 NULL
, /* vcons_free_screen */
112 NULL
, /* vcons_show_screen */
116 static void ofb_putpalreg(struct ofb_softc
*, int, uint8_t, uint8_t,
119 static int ofb_getcmap(struct ofb_softc
*, struct wsdisplay_cmap
*);
120 static int ofb_putcmap(struct ofb_softc
*, struct wsdisplay_cmap
*);
121 static void ofb_init_cmap(struct ofb_softc
*);
122 static int ofb_drm_print(void *, const char *);
124 extern const u_char rasops_cmap
[768];
126 extern int console_node
;
127 extern int console_instance
;
130 ofbmatch(struct device
*parent
, struct cfdata
*match
, void *aux
)
132 struct pci_attach_args
*pa
= aux
;
134 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_APPLE
&&
135 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_APPLE_CONTROL
)
138 if (PCI_CLASS(pa
->pa_class
) == PCI_CLASS_DISPLAY
)
145 ofbattach(struct device
*parent
, struct device
*self
, void *aux
)
147 struct ofb_softc
*sc
= (struct ofb_softc
*)self
;
148 struct pci_attach_args
*pa
= aux
;
149 struct wsemuldisplaydev_attach_args a
;
150 struct rasops_info
*ri
= &rascons_console_screen
.scr_ri
;
152 int console
, node
, sub
;
155 pci_devinfo(pa
->pa_id
, pa
->pa_class
, 0, devinfo
, sizeof(devinfo
));
156 printf(": %s\n", devinfo
);
158 if (console_node
== 0)
161 node
= pcidev_to_ofdev(pa
->pa_pc
, pa
->pa_tag
);
162 console
= (node
== console_node
);
164 /* check if any of the childs matches */
165 sub
= OF_child(node
);
166 while ((sub
!= 0) && (sub
!= console_node
)) {
169 if (sub
== console_node
) {
174 sc
->sc_memt
= pa
->pa_memt
;
175 sc
->sc_iot
= pa
->pa_iot
;
176 sc
->sc_pc
= pa
->pa_pc
;
177 sc
->sc_pcitag
= pa
->pa_tag
;
178 sc
->sc_mode
= WSDISPLAYIO_MODE_EMUL
;
183 vcons_init(&sc
->vd
, sc
, &rascons_stdscreen
, &ofb_accessops
);
184 sc
->vd
.init_screen
= ofb_init_screen
;
186 sc
->sc_node
= console_node
;
188 sc
->sc_ih
= console_instance
;
189 vcons_init_screen(&sc
->vd
, &rascons_console_screen
, 1, &defattr
);
190 rascons_console_screen
.scr_flags
|= VCONS_SCREEN_IS_STATIC
;
192 printf("%s: %d x %d, %dbpp\n", self
->dv_xname
,
193 ri
->ri_width
, ri
->ri_height
, ri
->ri_depth
);
196 if (OF_getprop(sc
->sc_node
, "address", &sc
->sc_fbaddr
, 4) != 4)
197 OF_interpret("frame-buffer-adr", 0, 1, &sc
->sc_fbaddr
);
198 if (sc
->sc_fbaddr
== 0) {
199 printf("%s: Unable to find the framebuffer address.\n",
200 sc
->sc_dev
.dv_xname
);
203 sc
->sc_fbsize
= round_page(ri
->ri_stride
* ri
->ri_height
);
206 if (OF_getprop(sc
->sc_node
, "assigned-addresses", sc
->sc_addrs
,
207 sizeof(sc
->sc_addrs
)) == -1) {
208 sc
->sc_node
= OF_parent(sc
->sc_node
);
209 OF_getprop(sc
->sc_node
, "assigned-addresses", sc
->sc_addrs
,
210 sizeof(sc
->sc_addrs
));
216 a
.scrdata
= &ofb_screenlist
;
217 a
.accessops
= &ofb_accessops
;
218 a
.accesscookie
= &sc
->vd
;
220 config_found(self
, &a
, wsemuldisplaydevprint
);
222 config_found_ia(self
, "drm", aux
, ofb_drm_print
);
226 ofb_drm_print(void *aux
, const char *pnp
)
229 aprint_normal("direct rendering for %s", pnp
);
234 ofb_init_screen(void *cookie
, struct vcons_screen
*scr
,
235 int existing
, long *defattr
)
237 struct ofb_softc
*sc
= cookie
;
238 struct rasops_info
*ri
= &scr
->scr_ri
;
240 if (scr
!= &rascons_console_screen
) {
241 rascons_init_rasops(sc
->sc_node
, ri
);
246 ofb_ioctl(void *v
, void *vs
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
248 struct vcons_data
*vd
= v
;
249 struct ofb_softc
*sc
= vd
->cookie
;
250 struct wsdisplay_fbinfo
*wdf
;
251 struct vcons_screen
*ms
= vd
->active
;
255 case WSDISPLAYIO_GTYPE
:
256 *(u_int
*)data
= WSDISPLAY_TYPE_PCIMISC
; /* XXX ? */
259 case WSDISPLAYIO_GINFO
:
260 /* we won't get here without any screen anyway */
263 wdf
->height
= ms
->scr_ri
.ri_height
;
264 wdf
->width
= ms
->scr_ri
.ri_width
;
265 wdf
->depth
= ms
->scr_ri
.ri_depth
;
271 case WSDISPLAYIO_GETCMAP
:
272 return ofb_getcmap(sc
, (struct wsdisplay_cmap
*)data
);
274 case WSDISPLAYIO_PUTCMAP
:
275 return ofb_putcmap(sc
, (struct wsdisplay_cmap
*)data
);
277 /* XXX There are no way to know framebuffer pa from a user program. */
281 memset(gm
, 0, sizeof(struct grfinfo
));
282 gm
->gd_fbaddr
= (void *)sc
->sc_fbaddr
;
283 gm
->gd_fbrowbytes
= ms
->scr_ri
.ri_stride
;
287 case WSDISPLAYIO_LINEBYTES
:
289 *(int *)data
= ms
->scr_ri
.ri_stride
;
292 case WSDISPLAYIO_SMODE
:
294 int new_mode
= *(int*)data
;
295 if (new_mode
!= sc
->sc_mode
)
297 sc
->sc_mode
= new_mode
;
298 if (new_mode
== WSDISPLAYIO_MODE_EMUL
)
301 vcons_redraw_screen(ms
);
306 /* PCI config read/write passthrough. */
307 case PCI_IOC_CFGREAD
:
308 case PCI_IOC_CFGWRITE
:
309 return (pci_devioctl(sc
->sc_pc
, sc
->sc_pcitag
,
310 cmd
, data
, flag
, l
));
316 ofb_mmap(void *v
, void *vs
, off_t offset
, int prot
)
318 struct vcons_data
*vd
= v
;
319 struct ofb_softc
*sc
= vd
->cookie
;
320 struct rasops_info
*ri
;
321 u_int32_t
*ap
= sc
->sc_addrs
;
324 if (vd
->active
== NULL
) {
325 printf("%s: no active screen.\n", sc
->sc_dev
.dv_xname
);
329 ri
= &vd
->active
->scr_ri
;
331 /* framebuffer at offset 0 */
332 if ((offset
>= 0) && (offset
< sc
->sc_fbsize
))
333 return bus_space_mmap(sc
->sc_memt
, sc
->sc_fbaddr
, offset
, prot
,
334 BUS_SPACE_MAP_LINEAR
);
337 * restrict all other mappings to processes with superuser privileges
338 * or the kernel itself
340 if (kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER
,
342 printf("%s: mmap() rejected.\n", sc
->sc_dev
.dv_xname
);
346 /* let them mmap() 0xa0000 - 0xbffff if it's not covered above */
347 #ifdef OFB_FAKE_VGA_FB
348 if (offset
>=0xa0000 && offset
< 0xbffff)
349 return sc
->sc_fbaddr
+ offset
- 0xa0000;
352 /* allow to map our IO space */
353 if ((offset
>= 0xf2000000) && (offset
< 0xf2800000)) {
354 return bus_space_mmap(sc
->sc_iot
, offset
-0xf2000000, 0, prot
,
355 BUS_SPACE_MAP_LINEAR
);
358 for (i
= 0; i
< 6; i
++) {
359 switch (ap
[0] & OFW_PCI_PHYS_HI_SPACEMASK
) {
360 case OFW_PCI_PHYS_HI_SPACE_MEM32
:
361 if (offset
>= ap
[2] && offset
< ap
[2] + ap
[4])
362 return bus_space_mmap(sc
->sc_memt
, offset
, 0,
363 prot
, BUS_SPACE_MAP_LINEAR
);
371 ofb_getcmap(struct ofb_softc
*sc
, struct wsdisplay_cmap
*cm
)
373 u_int index
= cm
->index
;
374 u_int count
= cm
->count
;
377 if (index
>= 256 || count
> 256 || index
+ count
> 256)
380 error
= copyout(&sc
->sc_cmap_red
[index
], cm
->red
, count
);
383 error
= copyout(&sc
->sc_cmap_green
[index
], cm
->green
, count
);
386 error
= copyout(&sc
->sc_cmap_blue
[index
], cm
->blue
, count
);
394 ofb_putcmap(struct ofb_softc
*sc
, struct wsdisplay_cmap
*cm
)
396 u_int index
= cm
->index
;
397 u_int count
= cm
->count
;
399 u_char rbuf
[256], gbuf
[256], bbuf
[256];
402 if (cm
->index
>= 256 || cm
->count
> 256 ||
403 (cm
->index
+ cm
->count
) > 256)
405 error
= copyin(cm
->red
, &rbuf
[index
], count
);
408 error
= copyin(cm
->green
, &gbuf
[index
], count
);
411 error
= copyin(cm
->blue
, &bbuf
[index
], count
);
415 memcpy(&sc
->sc_cmap_red
[index
], &rbuf
[index
], count
);
416 memcpy(&sc
->sc_cmap_green
[index
], &gbuf
[index
], count
);
417 memcpy(&sc
->sc_cmap_blue
[index
], &bbuf
[index
], count
);
419 r
= &sc
->sc_cmap_red
[index
];
420 g
= &sc
->sc_cmap_green
[index
];
421 b
= &sc
->sc_cmap_blue
[index
];
422 for (i
= 0; i
< count
; i
++) {
423 OF_call_method_1("color!", sc
->sc_ih
, 4, *r
, *g
, *b
, index
);
424 r
++, g
++, b
++, index
++;
430 ofb_putpalreg(struct ofb_softc
*sc
, int idx
, uint8_t r
, uint8_t g
, uint8_t b
)
432 if ((idx
<0) || (idx
> 255))
435 OF_call_method_1("color!", sc
->sc_ih
, 4, r
, g
, b
, idx
);
436 sc
->sc_cmap_red
[idx
] = r
;
437 sc
->sc_cmap_green
[idx
] = g
;
438 sc
->sc_cmap_blue
[idx
] = b
;
440 OF_call_method_1("color!", console_instance
, 4, r
, g
, b
, idx
);
445 ofb_init_cmap(struct ofb_softc
*sc
)
448 /* mess with the palette only when we're running in 8 bit */
449 if (rascons_console_screen
.scr_ri
.ri_depth
== 8) {
451 for (i
= 0; i
< 256; i
++) {
452 ofb_putpalreg(sc
, i
, rasops_cmap
[(i
* 3) + 0],
453 rasops_cmap
[(i
* 3) + 1],
454 rasops_cmap
[(i
* 3) + 2]);