1*0f9891f1Sjsg /* $OpenBSD: agp.c,v 1.51 2024/05/24 06:02:53 jsg Exp $ */
20139788eSmatthieu /*-
30139788eSmatthieu * Copyright (c) 2000 Doug Rabson
40139788eSmatthieu * All rights reserved.
50139788eSmatthieu *
60139788eSmatthieu * Redistribution and use in source and binary forms, with or without
70139788eSmatthieu * modification, are permitted provided that the following conditions
80139788eSmatthieu * are met:
90139788eSmatthieu * 1. Redistributions of source code must retain the above copyright
100139788eSmatthieu * notice, this list of conditions and the following disclaimer.
110139788eSmatthieu * 2. Redistributions in binary form must reproduce the above copyright
120139788eSmatthieu * notice, this list of conditions and the following disclaimer in the
130139788eSmatthieu * documentation and/or other materials provided with the distribution.
140139788eSmatthieu *
150139788eSmatthieu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
160139788eSmatthieu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
170139788eSmatthieu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
180139788eSmatthieu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
190139788eSmatthieu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
200139788eSmatthieu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
210139788eSmatthieu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
220139788eSmatthieu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
230139788eSmatthieu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
240139788eSmatthieu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
250139788eSmatthieu * SUCH DAMAGE.
260139788eSmatthieu *
270139788eSmatthieu * $FreeBSD: src/sys/pci/agp.c,v 1.12 2001/05/19 01:28:07 alfred Exp $
280139788eSmatthieu */
290139788eSmatthieu
300139788eSmatthieu #include <sys/param.h>
31d2e977c7Smpi #include <sys/systm.h>
320139788eSmatthieu #include <sys/malloc.h>
330139788eSmatthieu
34d2e977c7Smpi #include <uvm/uvm_extern.h>
350139788eSmatthieu
360139788eSmatthieu #include <dev/pci/pcivar.h>
370139788eSmatthieu
380139788eSmatthieu #include <dev/pci/agpvar.h>
390139788eSmatthieu #include <dev/pci/agpreg.h>
400139788eSmatthieu
418f6e6e82Soga void agp_attach(struct device *, struct device *, void *);
428f6e6e82Soga int agp_probe(struct device *, void *, void *);
430139788eSmatthieu
448f6e6e82Soga int agpvga_match(struct pci_attach_args *);
4540d7c10bSoga
468f6e6e82Soga int
agpdev_print(void * aux,const char * pnp)478f6e6e82Soga agpdev_print(void *aux, const char *pnp)
488f6e6e82Soga {
498f6e6e82Soga if (pnp) {
508f6e6e82Soga printf("agp at %s", pnp);
518f6e6e82Soga }
528f6e6e82Soga return (UNCONF);
538f6e6e82Soga }
5440d7c10bSoga
558f6e6e82Soga int
agpbus_probe(struct agp_attach_args * aa)568f6e6e82Soga agpbus_probe(struct agp_attach_args *aa)
578f6e6e82Soga {
588f6e6e82Soga struct pci_attach_args *pa = aa->aa_pa;
598f6e6e82Soga
608f6e6e82Soga if (strncmp(aa->aa_busname, "agp", 3) == 0 &&
618f6e6e82Soga PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
628f6e6e82Soga PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST)
638f6e6e82Soga return (1);
648f6e6e82Soga return (0);
658f6e6e82Soga }
668f6e6e82Soga
678f6e6e82Soga /*
688f6e6e82Soga * Find the video card hanging off the agp bus XXX assumes only one bus
698f6e6e82Soga */
708f6e6e82Soga int
agpvga_match(struct pci_attach_args * pa)718f6e6e82Soga agpvga_match(struct pci_attach_args *pa)
728f6e6e82Soga {
738f6e6e82Soga if (PCI_CLASS(pa->pa_class) == PCI_CLASS_DISPLAY &&
748f6e6e82Soga PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_DISPLAY_VGA) {
758f6e6e82Soga if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP,
768f6e6e82Soga NULL, NULL))
778f6e6e82Soga return (1);
788f6e6e82Soga }
798f6e6e82Soga return (0);
808f6e6e82Soga }
818f6e6e82Soga
828f6e6e82Soga struct device *
agp_attach_bus(struct pci_attach_args * pa,const struct agp_methods * methods,bus_addr_t apaddr,bus_size_t apsize,struct device * dev)838f6e6e82Soga agp_attach_bus(struct pci_attach_args *pa, const struct agp_methods *methods,
84b113917fSoga bus_addr_t apaddr, bus_size_t apsize, struct device *dev)
858f6e6e82Soga {
868f6e6e82Soga struct agpbus_attach_args arg;
878f6e6e82Soga
888f6e6e82Soga arg.aa_methods = methods;
898f6e6e82Soga arg.aa_pa = pa;
90d8cdf4a2Soga arg.aa_apaddr = apaddr;
91b113917fSoga arg.aa_apsize = apsize;
928f6e6e82Soga
938f6e6e82Soga printf("\n"); /* newline from the driver that called us */
948f6e6e82Soga return (config_found(dev, &arg, agpdev_print));
958f6e6e82Soga }
9640d7c10bSoga
9770456743Soga int
agp_probe(struct device * parent,void * match,void * aux)9840d7c10bSoga agp_probe(struct device *parent, void *match, void *aux)
9940d7c10bSoga {
1008f6e6e82Soga /*
1018f6e6e82Soga * we don't do any checking here, driver we're attaching this
1028f6e6e82Soga * interface to should have already done it.
1038f6e6e82Soga */
10440d7c10bSoga return (1);
10540d7c10bSoga }
1060139788eSmatthieu
1070139788eSmatthieu void
agp_attach(struct device * parent,struct device * self,void * aux)1080139788eSmatthieu agp_attach(struct device *parent, struct device *self, void *aux)
1090139788eSmatthieu {
1108f6e6e82Soga struct agpbus_attach_args *aa = aux;
1118f6e6e82Soga struct pci_attach_args *pa = aa->aa_pa;
11240d7c10bSoga struct agp_softc *sc = (struct agp_softc *)self;
1130139788eSmatthieu u_int memsize;
1148f6e6e82Soga int i;
1150139788eSmatthieu
1168f6e6e82Soga sc->sc_chipc = parent;
1178f6e6e82Soga sc->sc_methods = aa->aa_methods;
118d8cdf4a2Soga sc->sc_apaddr = aa->aa_apaddr;
119b113917fSoga sc->sc_apsize = aa->aa_apsize;
1208f6e6e82Soga
1210139788eSmatthieu static const int agp_max[][2] = {
1220139788eSmatthieu {0, 0},
1230139788eSmatthieu {32, 4},
1240139788eSmatthieu {64, 28},
1250139788eSmatthieu {128, 96},
1260139788eSmatthieu {256, 204},
1270139788eSmatthieu {512, 440},
1280139788eSmatthieu {1024, 942},
1290139788eSmatthieu {2048, 1920},
1300139788eSmatthieu {4096, 3932}
1310139788eSmatthieu };
1320139788eSmatthieu
1330139788eSmatthieu /*
1340139788eSmatthieu * Work out an upper bound for agp memory allocation. This
1350139788eSmatthieu * uses a heuristic table from the Linux driver.
1360139788eSmatthieu */
1370139788eSmatthieu memsize = ptoa(physmem) >> 20;
1380139788eSmatthieu
1399aa97624Sjasper for (i = 0; i < nitems(agp_max) && memsize > agp_max[i][0]; i++)
1400139788eSmatthieu ;
1419aa97624Sjasper if (i == nitems(agp_max))
1429aa97624Sjasper i = nitems(agp_max) - 1;
1430139788eSmatthieu sc->sc_maxmem = agp_max[i][1] << 20;
1440139788eSmatthieu
1450139788eSmatthieu sc->sc_pcitag = pa->pa_tag;
1460139788eSmatthieu sc->sc_pc = pa->pa_pc;
1470139788eSmatthieu sc->sc_id = pa->pa_id;
1480139788eSmatthieu sc->sc_dmat = pa->pa_dmat;
1494ad474a9Smpi sc->sc_memt = pa->pa_memt;
1500139788eSmatthieu
1510139788eSmatthieu pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_AGP,
1520139788eSmatthieu &sc->sc_capoff, NULL);
1530139788eSmatthieu
154d8cdf4a2Soga printf(": aperture at 0x%lx, size 0x%lx\n", (u_long)sc->sc_apaddr,
155b113917fSoga (u_long)sc->sc_apsize);
1560139788eSmatthieu }
1570139788eSmatthieu
1588d2c75e4Smpi const struct cfattach agp_ca = {
15940d7c10bSoga sizeof(struct agp_softc), agp_probe, agp_attach,
16040d7c10bSoga NULL, NULL
16140d7c10bSoga };
16240d7c10bSoga
16340d7c10bSoga struct cfdriver agp_cd = {
16440d7c10bSoga NULL, "agp", DV_DULL
16540d7c10bSoga };
16640d7c10bSoga
1670139788eSmatthieu struct agp_gatt *
agp_alloc_gatt(bus_dma_tag_t dmat,u_int32_t apsize)1688f6e6e82Soga agp_alloc_gatt(bus_dma_tag_t dmat, u_int32_t apsize)
1690139788eSmatthieu {
1700139788eSmatthieu struct agp_gatt *gatt;
1718f6e6e82Soga u_int32_t entries = apsize >> AGP_PAGE_SHIFT;
1720139788eSmatthieu
17340d7c10bSoga gatt = malloc(sizeof(*gatt), M_AGP, M_NOWAIT | M_ZERO);
1740139788eSmatthieu if (!gatt)
1750139788eSmatthieu return (NULL);
1760139788eSmatthieu gatt->ag_entries = entries;
177d4ab52b1Soga gatt->ag_size = entries * sizeof(u_int32_t);
1780139788eSmatthieu
179d4ab52b1Soga if (agp_alloc_dmamem(dmat, gatt->ag_size, &gatt->ag_dmamap,
180371e2336Sjsg &gatt->ag_physical, &gatt->ag_dmaseg) != 0) {
1811f3c0a0aSderaadt free(gatt, M_AGP, sizeof *gatt);
18240d7c10bSoga return (NULL);
183371e2336Sjsg }
1840139788eSmatthieu
185d4ab52b1Soga if (bus_dmamem_map(dmat, &gatt->ag_dmaseg, 1, gatt->ag_size,
186d4ab52b1Soga (caddr_t *)&gatt->ag_virtual, BUS_DMA_NOWAIT) != 0) {
187d4ab52b1Soga agp_free_dmamem(dmat, gatt->ag_size, gatt->ag_dmamap,
188d4ab52b1Soga &gatt->ag_dmaseg);
1891f3c0a0aSderaadt free(gatt, M_AGP, sizeof *gatt);
190d4ab52b1Soga return (NULL);
191d4ab52b1Soga }
192d4ab52b1Soga
1930139788eSmatthieu agp_flush_cache();
1940139788eSmatthieu
19540d7c10bSoga return (gatt);
1960139788eSmatthieu }
1970139788eSmatthieu
1980139788eSmatthieu void
agp_free_gatt(bus_dma_tag_t dmat,struct agp_gatt * gatt)1998f6e6e82Soga agp_free_gatt(bus_dma_tag_t dmat, struct agp_gatt *gatt)
2000139788eSmatthieu {
201d4ab52b1Soga bus_dmamem_unmap(dmat, (caddr_t)gatt->ag_virtual, gatt->ag_size);
202d4ab52b1Soga agp_free_dmamem(dmat, gatt->ag_size, gatt->ag_dmamap, &gatt->ag_dmaseg);
2031f3c0a0aSderaadt free(gatt, M_AGP, sizeof *gatt);
2040139788eSmatthieu }
2050139788eSmatthieu
2060139788eSmatthieu int
agp_generic_enable(struct agp_softc * sc,u_int32_t mode)20740d7c10bSoga agp_generic_enable(struct agp_softc *sc, u_int32_t mode)
2080139788eSmatthieu {
2098f6e6e82Soga struct pci_attach_args pa;
2108f6e6e82Soga pcireg_t tstatus, mstatus, command;
2110139788eSmatthieu int rq, sba, fw, rate, capoff;
2120139788eSmatthieu
2138f6e6e82Soga if (pci_find_device(&pa, agpvga_match) == 0 ||
2148f6e6e82Soga pci_get_capability(pa.pa_pc, pa.pa_tag, PCI_CAP_AGP,
2150139788eSmatthieu &capoff, NULL) == 0) {
2160139788eSmatthieu printf("agp_generic_enable: not an AGP capable device\n");
21740d7c10bSoga return (-1);
2180139788eSmatthieu }
2190139788eSmatthieu
2200139788eSmatthieu tstatus = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
2210139788eSmatthieu sc->sc_capoff + AGP_STATUS);
22260d13d3bSoga /* display agp mode */
2238f6e6e82Soga mstatus = pci_conf_read(pa.pa_pc, pa.pa_tag,
2240139788eSmatthieu capoff + AGP_STATUS);
2250139788eSmatthieu
2260139788eSmatthieu /* Set RQ to the min of mode, tstatus and mstatus */
2270139788eSmatthieu rq = AGP_MODE_GET_RQ(mode);
2280139788eSmatthieu if (AGP_MODE_GET_RQ(tstatus) < rq)
2290139788eSmatthieu rq = AGP_MODE_GET_RQ(tstatus);
2300139788eSmatthieu if (AGP_MODE_GET_RQ(mstatus) < rq)
2310139788eSmatthieu rq = AGP_MODE_GET_RQ(mstatus);
2320139788eSmatthieu
2330139788eSmatthieu /* Set SBA if all three can deal with SBA */
2340139788eSmatthieu sba = (AGP_MODE_GET_SBA(tstatus)
2350139788eSmatthieu & AGP_MODE_GET_SBA(mstatus)
2360139788eSmatthieu & AGP_MODE_GET_SBA(mode));
2370139788eSmatthieu
2380139788eSmatthieu /* Similar for FW */
2390139788eSmatthieu fw = (AGP_MODE_GET_FW(tstatus)
2400139788eSmatthieu & AGP_MODE_GET_FW(mstatus)
2410139788eSmatthieu & AGP_MODE_GET_FW(mode));
2420139788eSmatthieu
2430139788eSmatthieu /* Figure out the max rate */
2440139788eSmatthieu rate = (AGP_MODE_GET_RATE(tstatus)
2450139788eSmatthieu & AGP_MODE_GET_RATE(mstatus)
2460139788eSmatthieu & AGP_MODE_GET_RATE(mode));
2470139788eSmatthieu if (rate & AGP_MODE_RATE_4x)
2480139788eSmatthieu rate = AGP_MODE_RATE_4x;
2490139788eSmatthieu else if (rate & AGP_MODE_RATE_2x)
2500139788eSmatthieu rate = AGP_MODE_RATE_2x;
2510139788eSmatthieu else
2520139788eSmatthieu rate = AGP_MODE_RATE_1x;
2530139788eSmatthieu
2540139788eSmatthieu /* Construct the new mode word and tell the hardware */
2550139788eSmatthieu command = AGP_MODE_SET_RQ(0, rq);
2560139788eSmatthieu command = AGP_MODE_SET_SBA(command, sba);
2570139788eSmatthieu command = AGP_MODE_SET_FW(command, fw);
2580139788eSmatthieu command = AGP_MODE_SET_RATE(command, rate);
2590139788eSmatthieu command = AGP_MODE_SET_AGP(command, 1);
26060d13d3bSoga
2610139788eSmatthieu pci_conf_write(sc->sc_pc, sc->sc_pcitag,
2620139788eSmatthieu sc->sc_capoff + AGP_COMMAND, command);
2638f6e6e82Soga pci_conf_write(pa.pa_pc, pa.pa_tag, capoff + AGP_COMMAND, command);
26440d7c10bSoga return (0);
2650139788eSmatthieu }
2660139788eSmatthieu
267d4ab52b1Soga /*
268d4ab52b1Soga * Allocates a single-segment block of zeroed, wired dma memory.
269d4ab52b1Soga */
2700139788eSmatthieu int
agp_alloc_dmamem(bus_dma_tag_t tag,size_t size,bus_dmamap_t * mapp,bus_addr_t * baddr,bus_dma_segment_t * seg)271d4ab52b1Soga agp_alloc_dmamem(bus_dma_tag_t tag, size_t size, bus_dmamap_t *mapp,
272d4ab52b1Soga bus_addr_t *baddr, bus_dma_segment_t *seg)
2730139788eSmatthieu {
274d4ab52b1Soga int error, level = 0, nseg;
2750139788eSmatthieu
2760139788eSmatthieu if ((error = bus_dmamem_alloc(tag, size, PAGE_SIZE, 0,
277d4ab52b1Soga seg, 1, &nseg, BUS_DMA_NOWAIT | BUS_DMA_ZERO)) != 0)
2780139788eSmatthieu goto out;
2790139788eSmatthieu level++;
2800139788eSmatthieu
281d4ab52b1Soga if ((error = bus_dmamap_create(tag, size, nseg, size, 0,
2820139788eSmatthieu BUS_DMA_NOWAIT, mapp)) != 0)
2830139788eSmatthieu goto out;
2840139788eSmatthieu level++;
2850139788eSmatthieu
286d4ab52b1Soga if ((error = bus_dmamap_load_raw(tag, *mapp, seg, nseg, size,
2870139788eSmatthieu BUS_DMA_NOWAIT)) != 0)
2880139788eSmatthieu goto out;
2890139788eSmatthieu
2900139788eSmatthieu *baddr = (*mapp)->dm_segs[0].ds_addr;
2910139788eSmatthieu
29240d7c10bSoga return (0);
2930139788eSmatthieu out:
2940139788eSmatthieu switch (level) {
295d4ab52b1Soga case 2:
2960139788eSmatthieu bus_dmamap_destroy(tag, *mapp);
2970139788eSmatthieu /* FALLTHROUGH */
2980139788eSmatthieu case 1:
299d4ab52b1Soga bus_dmamem_free(tag, seg, nseg);
3000139788eSmatthieu break;
3010139788eSmatthieu default:
3020139788eSmatthieu break;
3030139788eSmatthieu }
3040139788eSmatthieu
30540d7c10bSoga return (error);
3060139788eSmatthieu }
3070139788eSmatthieu
3080139788eSmatthieu void
agp_free_dmamem(bus_dma_tag_t tag,size_t size,bus_dmamap_t map,bus_dma_segment_t * seg)3090139788eSmatthieu agp_free_dmamem(bus_dma_tag_t tag, size_t size, bus_dmamap_t map,
310d4ab52b1Soga bus_dma_segment_t *seg)
3110139788eSmatthieu {
3120139788eSmatthieu bus_dmamap_unload(tag, map);
3130139788eSmatthieu bus_dmamap_destroy(tag, map);
314d4ab52b1Soga bus_dmamem_free(tag, seg, 1);
3150139788eSmatthieu }
31640d7c10bSoga
31740d7c10bSoga /* Implementation of the kernel api */
31840d7c10bSoga
31940d7c10bSoga void *
agp_find_device(int unit)32040d7c10bSoga agp_find_device(int unit)
32140d7c10bSoga {
3228f8e4ea1Soga if (unit >= agp_cd.cd_ndevs || unit < 0)
3238f8e4ea1Soga return (NULL);
3248f8e4ea1Soga return (agp_cd.cd_devs[unit]);
32540d7c10bSoga }
32640d7c10bSoga
32740d7c10bSoga enum agp_acquire_state
agp_state(void * dev)32840d7c10bSoga agp_state(void *dev)
32940d7c10bSoga {
33040d7c10bSoga struct agp_softc *sc = (struct agp_softc *) dev;
33140d7c10bSoga return (sc->sc_state);
33240d7c10bSoga }
33340d7c10bSoga
33440d7c10bSoga void
agp_get_info(void * dev,struct agp_info * info)33540d7c10bSoga agp_get_info(void *dev, struct agp_info *info)
33640d7c10bSoga {
33740d7c10bSoga struct agp_softc *sc = (struct agp_softc *)dev;
33840d7c10bSoga
3398f6e6e82Soga if (sc->sc_capoff != 0)
34040d7c10bSoga info->ai_mode = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
3418f6e6e82Soga AGP_STATUS + sc->sc_capoff);
3428f6e6e82Soga else
3438f6e6e82Soga info->ai_mode = 0; /* i810 doesn't have real AGP */
34440d7c10bSoga info->ai_aperture_base = sc->sc_apaddr;
345b113917fSoga info->ai_aperture_size = sc->sc_apsize;
34640d7c10bSoga info->ai_memory_allowed = sc->sc_maxmem;
34740d7c10bSoga info->ai_memory_used = sc->sc_allocated;
34885ff9379Sjsg info->ai_devid = sc->sc_id;
34940d7c10bSoga }
35040d7c10bSoga
35140d7c10bSoga int
agp_acquire(void * dev)35240d7c10bSoga agp_acquire(void *dev)
35340d7c10bSoga {
35440d7c10bSoga struct agp_softc *sc = (struct agp_softc *)dev;
355e47997a5Soga
356124620abSkettenis if (sc->sc_chipc == NULL)
357124620abSkettenis return (EINVAL);
358124620abSkettenis
359124620abSkettenis if (sc->sc_state != AGP_ACQUIRE_FREE)
360124620abSkettenis return (EBUSY);
361124620abSkettenis sc->sc_state = AGP_ACQUIRE_KERNEL;
362124620abSkettenis
363124620abSkettenis return (0);
36440d7c10bSoga }
36540d7c10bSoga
36640d7c10bSoga int
agp_release(void * dev)36740d7c10bSoga agp_release(void *dev)
36840d7c10bSoga {
36940d7c10bSoga struct agp_softc *sc = (struct agp_softc *)dev;
370e47997a5Soga
371124620abSkettenis if (sc->sc_state == AGP_ACQUIRE_FREE)
372124620abSkettenis return (0);
373124620abSkettenis
374124620abSkettenis if (sc->sc_state != AGP_ACQUIRE_KERNEL)
375124620abSkettenis return (EBUSY);
376124620abSkettenis
377124620abSkettenis sc->sc_state = AGP_ACQUIRE_FREE;
378124620abSkettenis return (0);
37940d7c10bSoga }
38040d7c10bSoga
38140d7c10bSoga int
agp_enable(void * dev,u_int32_t mode)38240d7c10bSoga agp_enable(void *dev, u_int32_t mode)
38340d7c10bSoga {
384678c000dSoga struct agp_softc *sc = dev;
385678c000dSoga int ret;
386e47997a5Soga
387678c000dSoga if (sc->sc_methods->enable != NULL) {
388678c000dSoga ret = sc->sc_methods->enable(sc->sc_chipc, mode);
389678c000dSoga } else {
390678c000dSoga ret = agp_generic_enable(sc, mode);
391678c000dSoga }
392678c000dSoga return (ret);
39340d7c10bSoga }
39440d7c10bSoga
3954ad474a9Smpi paddr_t
agp_mmap(struct agp_softc * sc,off_t off,int prot)3964ad474a9Smpi agp_mmap(struct agp_softc *sc, off_t off, int prot)
3974ad474a9Smpi {
3984ad474a9Smpi if (sc->sc_chipc == NULL)
3994ad474a9Smpi return (-1);
4004ad474a9Smpi
4014ad474a9Smpi if (off >= sc->sc_apsize)
4024ad474a9Smpi return (-1);
4034ad474a9Smpi
404124620abSkettenis if (sc->sc_apaddr == 0)
4054ad474a9Smpi return (-1);
4064ad474a9Smpi
407124620abSkettenis return bus_space_mmap(sc->sc_memt, sc->sc_apaddr, off, prot, 0);
4084ad474a9Smpi }
409