1 /* $NetBSD: genfb_pci.c,v 1.22 2009/08/24 11:03:44 jmcneill Exp $ */
4 * Copyright (c) 2007 Michael Lorenz
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: genfb_pci.c,v 1.22 2009/08/24 11:03:44 jmcneill Exp $");
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/device.h>
37 #include <sys/mutex.h>
38 #include <sys/ioctl.h>
39 #include <sys/kernel.h>
40 #include <sys/systm.h>
41 #include <sys/kauth.h>
43 #include <dev/pci/pcidevs.h>
44 #include <dev/pci/pcireg.h>
45 #include <dev/pci/pcivar.h>
46 #include <dev/pci/pciio.h>
48 #include <dev/wsfb/genfbvar.h>
50 #include <dev/pci/genfb_pcivar.h>
53 #include "opt_genfb.h"
55 #ifdef GENFB_PCI_DEBUG
56 # define DPRINTF printf
58 # define DPRINTF while (0) printf
61 static int pci_genfb_match(device_t
, cfdata_t
, void *);
62 static void pci_genfb_attach(device_t
, device_t
, void *);
63 static int pci_genfb_ioctl(void *, void *, u_long
, void *, int,
65 static paddr_t
pci_genfb_mmap(void *, void *, off_t
, int);
66 static int pci_genfb_borrow(void *, bus_addr_t
, bus_space_handle_t
*);
67 static int pci_genfb_drm_print(void *, const char *);
69 CFATTACH_DECL(genfb_pci
, sizeof(struct pci_genfb_softc
),
70 pci_genfb_match
, pci_genfb_attach
, NULL
, NULL
);
73 pci_genfb_match(device_t parent
, cfdata_t match
, void *aux
)
75 struct pci_attach_args
*pa
= aux
;
78 if (!genfb_is_enabled())
79 return 0; /* explicitly disabled by MD code */
81 if (genfb_is_console())
82 matchlvl
= 5; /* beat VGA */
84 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_APPLE
&&
85 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_APPLE_CONTROL
)
88 if (PCI_CLASS(pa
->pa_class
) == PCI_CLASS_DISPLAY
)
95 pci_genfb_attach(device_t parent
, device_t self
, void *aux
)
97 struct pci_genfb_softc
*sc
= device_private(self
);
98 struct pci_attach_args
*pa
= aux
;
103 pci_devinfo(pa
->pa_id
, pa
->pa_class
, 0, devinfo
, sizeof(devinfo
));
105 aprint_normal(": %s\n", devinfo
);
107 sc
->sc_memt
= pa
->pa_memt
;
108 sc
->sc_iot
= pa
->pa_iot
;
109 sc
->sc_pc
= pa
->pa_pc
;
110 sc
->sc_pcitag
= pa
->pa_tag
;
111 sc
->sc_want_wsfb
= 0;
113 genfb_init(&sc
->sc_gen
);
115 /* firmware / MD code responsible for restoring the display */
116 if (sc
->sc_gen
.sc_pmfcb
== NULL
)
117 pmf_device_register(self
, NULL
, NULL
);
119 pmf_device_register(self
,
120 sc
->sc_gen
.sc_pmfcb
->gpc_suspend
,
121 sc
->sc_gen
.sc_pmfcb
->gpc_resume
);
123 if ((sc
->sc_gen
.sc_width
== 0) || (sc
->sc_gen
.sc_fbsize
== 0)) {
124 aprint_debug_dev(self
, "not configured by firmware\n");
128 if (bus_space_map(sc
->sc_memt
, sc
->sc_gen
.sc_fboffset
,
129 sc
->sc_gen
.sc_fbsize
, BUS_SPACE_MAP_LINEAR
, &sc
->sc_memh
) != 0) {
131 aprint_error_dev(self
, "unable to map the framebuffer\n");
134 sc
->sc_gen
.sc_fbaddr
= bus_space_vaddr(sc
->sc_memt
, sc
->sc_memh
);
136 /* mmap()able bus ranges */
141 type
= pci_mapreg_type(sc
->sc_pc
, sc
->sc_pcitag
, bar
);
142 if ((type
== PCI_MAPREG_TYPE_MEM
) ||
143 (type
== PCI_MAPREG_TYPE_ROM
)) {
145 pci_mapreg_info(sc
->sc_pc
, sc
->sc_pcitag
, bar
, type
,
146 &sc
->sc_ranges
[idx
].offset
,
147 &sc
->sc_ranges
[idx
].size
,
148 &sc
->sc_ranges
[idx
].flags
);
151 sc
->sc_bars
[(bar
- 0x10) >> 2] =
152 pci_conf_read(sc
->sc_pc
, sc
->sc_pcitag
, bar
);
155 sc
->sc_ranges_used
= idx
;
157 ops
.genfb_ioctl
= pci_genfb_ioctl
;
158 ops
.genfb_mmap
= pci_genfb_mmap
;
159 ops
.genfb_borrow
= pci_genfb_borrow
;
161 if (genfb_attach(&sc
->sc_gen
, &ops
) == 0) {
163 /* now try to attach a DRM */
164 config_found_ia(self
, "drm", aux
, pci_genfb_drm_print
);
169 pci_genfb_drm_print(void *aux
, const char *pnp
)
172 aprint_normal("drm at %s", pnp
);
178 pci_genfb_ioctl(void *v
, void *vs
, u_long cmd
, void *data
, int flag
,
181 struct pci_genfb_softc
*sc
= v
;
184 case WSDISPLAYIO_GTYPE
:
185 *(u_int
*)data
= WSDISPLAY_TYPE_PCIMISC
;
188 /* PCI config read/write passthrough. */
189 case PCI_IOC_CFGREAD
:
190 case PCI_IOC_CFGWRITE
:
191 return (pci_devioctl(sc
->sc_pc
, sc
->sc_pcitag
,
192 cmd
, data
, flag
, l
));
193 case WSDISPLAYIO_SMODE
:
195 int new_mode
= *(int*)data
, i
;
196 if (new_mode
== WSDISPLAYIO_MODE_EMUL
) {
197 for (i
= 0; i
< 9; i
++)
198 pci_conf_write(sc
->sc_pc
,
211 pci_genfb_mmap(void *v
, void *vs
, off_t offset
, int prot
)
213 struct pci_genfb_softc
*sc
= v
;
218 sc
->sc_want_wsfb
= 1;
221 * regular fb mapping at 0
222 * since some Sun firmware likes to put PCI resources low enough
223 * to collide with the wsfb mapping we only allow it after asking
226 DPRINTF("%s: %08x limit %08x\n", __func__
, (uint32_t)offset
,
227 (uint32_t)sc
->sc_gen
.sc_fbsize
);
228 if ((offset
>= 0) && (offset
< sc
->sc_gen
.sc_fbsize
) &&
229 (sc
->sc_want_wsfb
== 1)) {
231 return bus_space_mmap(sc
->sc_memt
, sc
->sc_gen
.sc_fboffset
,
232 offset
, prot
, BUS_SPACE_MAP_LINEAR
);
236 * restrict all other mappings to processes with superuser privileges
237 * or the kernel itself
239 if (kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER
,
241 aprint_normal_dev(&sc
->sc_gen
.sc_dev
, "mmap() rejected.\n");
245 #ifdef WSFB_FAKE_VGA_FB
246 if ((offset
>= 0xa0000) && (offset
< 0xbffff)) {
248 return bus_space_mmap(sc
->sc_memt
, sc
->sc_gen
.sc_fboffset
,
249 offset
- 0xa0000, prot
, BUS_SPACE_MAP_LINEAR
);
254 * XXX this should be generalized, let's just
255 * #define PCI_IOAREA_PADDR
256 * #define PCI_IOAREA_OFFSET
257 * #define PCI_IOAREA_SIZE
258 * somewhere in a MD header and compile this code only if all are
261 #ifdef PCI_MAGIC_IO_RANGE
262 /* allow to map our IO space */
263 if ((offset
>= PCI_MAGIC_IO_RANGE
) &&
264 (offset
< PCI_MAGIC_IO_RANGE
+ 0x10000)) {
265 return bus_space_mmap(sc
->sc_iot
, offset
- PCI_MAGIC_IO_RANGE
,
266 0, prot
, BUS_SPACE_MAP_LINEAR
);
270 /* allow to mmap() our BARs */
271 /* maybe the ROM BAR too? */
272 for (i
= 0; i
< sc
->sc_ranges_used
; i
++) {
274 r
= &sc
->sc_ranges
[i
];
275 if ((offset
>= r
->offset
) && (offset
< (r
->offset
+ r
->size
))) {
276 return bus_space_mmap(sc
->sc_memt
, offset
, 0, prot
,
285 pci_genfb_borrow(void *opaque
, bus_addr_t addr
, bus_space_handle_t
*hdlp
)
287 struct pci_genfb_softc
*sc
= opaque
;
291 if (!sc
->sc_gen
.sc_fboffset
)
293 if (sc
->sc_gen
.sc_fboffset
!= addr
)