[BACK]Return to s3c2800_pci.c CVS log [TXT][DIR] Up to [local] / sys / arch / arm / s3c2xx0

Annotation of sys/arch/arm/s3c2xx0/s3c2800_pci.c, Revision 1.1

1.1     ! nbrk        1: /*     $NetBSD: s3c2800_pci.c,v 1.12 2007/03/04 05:59:38 christos Exp $        */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2002 Fujitsu Component Limited
        !             5:  * Copyright (c) 2002 Genetec Corporation
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            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. Neither the name of The Fujitsu Component Limited nor the name of
        !            17:  *    Genetec corporation may not be used to endorse or promote products
        !            18:  *    derived from this software without specific prior written permission.
        !            19:  *
        !            20:  * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC
        !            21:  * CORPORATION ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
        !            22:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
        !            23:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
        !            24:  * DISCLAIMED.  IN NO EVENT SHALL FUJITSU COMPONENT LIMITED OR GENETEC
        !            25:  * CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
        !            26:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
        !            27:  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
        !            28:  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
        !            29:  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
        !            30:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
        !            31:  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            32:  * SUCH DAMAGE.
        !            33:  *
        !            34:  * derived from evbarm/ifpga/ifpga_pci.c
        !            35:  */
        !            36:
        !            37: /*
        !            38:  * Copyright (c) 2001 ARM Ltd
        !            39:  * All rights reserved.
        !            40:  *
        !            41:  * Redistribution and use in source and binary forms, with or without
        !            42:  * modification, are permitted provided that the following conditions
        !            43:  * are met:
        !            44:  * 1. Redistributions of source code must retain the above copyright
        !            45:  *    notice, this list of conditions and the following disclaimer.
        !            46:  * 2. Redistributions in binary form must reproduce the above copyright
        !            47:  *    notice, this list of conditions and the following disclaimer in the
        !            48:  *    documentation and/or other materials provided with the distribution.
        !            49:  * 3. The name of the company may not be used to endorse or promote
        !            50:  *    products derived from this software without specific prior written
        !            51:  *    permission.
        !            52:  *
        !            53:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
        !            54:  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
        !            55:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            56:  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
        !            57:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            58:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            59:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            60:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            61:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            62:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            63:  * SUCH DAMAGE.
        !            64:  *
        !            65:  * Copyright (c) 1997,1998 Mark Brinicombe.
        !            66:  * Copyright (c) 1997,1998 Causality Limited
        !            67:  * All rights reserved.
        !            68:  *
        !            69:  * Redistribution and use in source and binary forms, with or without
        !            70:  * modification, are permitted provided that the following conditions
        !            71:  * are met:
        !            72:  * 1. Redistributions of source code must retain the above copyright
        !            73:  *    notice, this list of conditions and the following disclaimer.
        !            74:  * 2. Redistributions in binary form must reproduce the above copyright
        !            75:  *    notice, this list of conditions and the following disclaimer in the
        !            76:  *    documentation and/or other materials provided with the distribution.
        !            77:  * 3. All advertising materials mentioning features or use of this software
        !            78:  *    must display the following acknowledgement:
        !            79:  *     This product includes software developed by Mark Brinicombe
        !            80:  *     for the NetBSD Project.
        !            81:  * 4. The name of the company nor the name of the author may be used to
        !            82:  *    endorse or promote products derived from this software without specific
        !            83:  *    prior written permission.
        !            84:  *
        !            85:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
        !            86:  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
        !            87:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            88:  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
        !            89:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            90:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            91:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            92:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            93:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            94:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            95:  * SUCH DAMAGE.
        !            96:  */
        !            97:
        !            98: /*
        !            99:  * PCI configuration support for Samsung s3c2800.
        !           100:  */
        !           101:
        !           102: #include <sys/cdefs.h>
        !           103: __KERNEL_RCSID(0, "$NetBSD: s3c2800_pci.c,v 1.12 2007/03/04 05:59:38 christos Exp $");
        !           104:
        !           105: #include <sys/param.h>
        !           106: #include <sys/systm.h>
        !           107: #include <sys/kernel.h>
        !           108: #include <sys/device.h>
        !           109: #include <sys/extent.h>
        !           110: #include <sys/malloc.h>
        !           111:
        !           112: #include <uvm/uvm_extern.h>
        !           113:
        !           114: #include <machine/bus.h>
        !           115:
        !           116: #include <arm/s3c2xx0/s3c2800reg.h>
        !           117: #include <arm/s3c2xx0/s3c2800var.h>
        !           118:
        !           119: #include <dev/pci/pcireg.h>
        !           120: #include <dev/pci/pciconf.h>
        !           121:
        !           122: #include "opt_pci.h"
        !           123: #include "pci.h"
        !           124:
        !           125: /*
        !           126:  * pci tag encoding.
        !           127:  * also useful for configuration type 0 address
        !           128:  */
        !           129: #define BUSNO_SHIFT    16
        !           130: #define BUSNO_MASK     (0xff<<BUSNO_SHIFT)
        !           131: #define DEVNO_SHIFT    11
        !           132: #define DEVNO_MASK     (0x1f<<DEVNO_SHIFT)
        !           133: #define tag_to_devno(tag)      (((tag)&DEVNO_MASK)>>DEVNO_SHIFT)
        !           134: #define FUNNO_SHIFT    8
        !           135: #define FUNNO_MASK     (0x07<<FUNNO_SHIFT)
        !           136:
        !           137: #define BUS0_DEV_MIN   1
        !           138: #define BUS0_DEV_MAX   21
        !           139:
        !           140: void   s3c2800_pci_attach_hook(struct device *, struct device *,
        !           141:                                struct pcibus_attach_args *);
        !           142: int    s3c2800_pci_bus_maxdevs(void *, int);
        !           143: pcitag_t s3c2800_pci_make_tag(void *, int, int, int);
        !           144: void   s3c2800_pci_decompose_tag(void *, pcitag_t, int *, int *, int *);
        !           145: pcireg_t s3c2800_pci_conf_read(void *, pcitag_t, int);
        !           146: void   s3c2800_pci_conf_write(void *, pcitag_t, int, pcireg_t);
        !           147: int    s3c2800_pci_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
        !           148: const char *s3c2800_pci_intr_string(void *, pci_intr_handle_t);
        !           149: const struct evcnt *s3c2800_pci_intr_evcnt(void *, pci_intr_handle_t);
        !           150: void *s3c2800_pci_intr_establish(void *, pci_intr_handle_t, int,
        !           151:                                  int (*) (void *), void *);
        !           152: void   s3c2800_pci_intr_disestablish(void *, void *);
        !           153:
        !           154: #define        PCI_CONF_LOCK(s)        (s) = disable_interrupts(I32_bit)
        !           155: #define        PCI_CONF_UNLOCK(s)      restore_interrupts((s))
        !           156:
        !           157: struct sspci_irq_handler {
        !           158:        int (*func) (void *);
        !           159:        void *arg;
        !           160:        int level;
        !           161:        SLIST_ENTRY(sspci_irq_handler) link;
        !           162: };
        !           163:
        !           164: struct sspci_softc {
        !           165:        struct device sc_dev;
        !           166:
        !           167:        bus_space_tag_t sc_iot;
        !           168:        bus_space_handle_t sc_reg_ioh;
        !           169:        bus_space_handle_t sc_conf0_ioh;        /* config type0 space */
        !           170:        bus_space_handle_t sc_conf1_ioh;        /* config type1 space */
        !           171:
        !           172:        uint32_t sc_pciinten;   /* copy of PCIINTEN register */
        !           173:
        !           174:        /* list of interrupt handlers. SLIST is not good for removing
        !           175:         * element from it, but intr_disestablish is rarely called */
        !           176:        SLIST_HEAD(, sspci_irq_handler) sc_irq_handlers;
        !           177:
        !           178:        void *sc_softinterrupt;
        !           179: };
        !           180:
        !           181: static int sspci_match(struct device *, struct cfdata *, void *aux);
        !           182: static void sspci_attach(struct device *, struct device *, void *);
        !           183:
        !           184: static int sspci_bs_map(void *, bus_addr_t, bus_size_t, int,
        !           185:                             bus_space_handle_t *);
        !           186: static int sspci_init_controller(struct sspci_softc *);
        !           187: static int sspci_intr(void *);
        !           188: static void sspci_softintr(void *);
        !           189:
        !           190: /* attach structures */
        !           191: CFATTACH_DECL(sspci, sizeof(struct sspci_softc), sspci_match, sspci_attach,
        !           192:     NULL, NULL);
        !           193:
        !           194:
        !           195: struct arm32_pci_chipset sspci_chipset = {
        !           196:        NULL,           /* conf_v */
        !           197:        s3c2800_pci_attach_hook,
        !           198:        s3c2800_pci_bus_maxdevs,
        !           199:        s3c2800_pci_make_tag,
        !           200:        s3c2800_pci_decompose_tag,
        !           201:        s3c2800_pci_conf_read,
        !           202:        s3c2800_pci_conf_write,
        !           203:        NULL,           /* intr_v */
        !           204:        s3c2800_pci_intr_map,
        !           205:        s3c2800_pci_intr_string,
        !           206:        s3c2800_pci_intr_evcnt,
        !           207:        s3c2800_pci_intr_establish,
        !           208:        s3c2800_pci_intr_disestablish
        !           209: };
        !           210:
        !           211:
        !           212: /*
        !           213:  * bus space tag for PCI IO/Memory access space.
        !           214:  * filled in by sspci_attach()
        !           215:  */
        !           216: struct bus_space sspci_io_tag, sspci_mem_tag;
        !           217:
        !           218: static int
        !           219: sspci_match(struct device *parent, struct cfdata *match, void *aux)
        !           220: {
        !           221:        return 1;
        !           222: }
        !           223:
        !           224: static void
        !           225: sspci_attach(struct device *parent, struct device *self, void *aux)
        !           226: {
        !           227:        struct sspci_softc *sc = (struct sspci_softc *) self;
        !           228:        struct s3c2xx0_attach_args *aa = aux;
        !           229:        bus_space_tag_t iot;
        !           230:        bus_dma_tag_t pci_dma_tag;
        !           231:        const char *error_on;   /* for panic message */
        !           232: #if defined(PCI_NETBSD_CONFIGURE)
        !           233:        struct extent *ioext, *memext;
        !           234:        struct pcibus_attach_args pci_pba;
        !           235: #endif
        !           236:
        !           237: #define FAIL(which)  do { \
        !           238:        error_on=(which); goto abort; }while(/*CONSTCOND*/0)
        !           239:
        !           240:        iot = sc->sc_iot = aa->sa_iot;
        !           241:        if (bus_space_map(iot, S3C2800_PCICTL_BASE,
        !           242:                S3C2800_PCICTL_SIZE, 0, &sc->sc_reg_ioh))
        !           243:                FAIL("control regs");
        !           244:
        !           245:        if (bus_space_map(iot, S3C2800_PCI_CONF0_BASE,
        !           246:                S3C2800_PCI_CONF0_SIZE, 0, &sc->sc_conf0_ioh))
        !           247:                FAIL("config type 0 area");
        !           248:
        !           249: #if 0
        !           250:        if (bus_space_map(iot, S3C2800_PCI_CONF1_BASE,
        !           251:                S3C2800_PCI_CONF1_SIZE, 0, &sc->sc_conf1_ioh))
        !           252:                FAIL("config type 1 area");
        !           253: #endif
        !           254:        printf("\n");
        !           255:
        !           256:        SLIST_INIT(&sc->sc_irq_handlers);
        !           257:        if (!s3c2800_intr_establish(S3C2800_INT_PCI, IPL_AUDIO, IST_LEVEL,
        !           258:                sspci_intr, sc))
        !           259:                FAIL("intr_establish");
        !           260:
        !           261:        sc->sc_softinterrupt = softintr_establish(IPL_SOFT,
        !           262:            sspci_softintr, sc);
        !           263:        if (sc->sc_softinterrupt == NULL)
        !           264:                FAIL("softintr_establish");
        !           265:
        !           266: #if defined(PCI_NETBSD_CONFIGURE)
        !           267:        if (sspci_init_controller(sc)) {
        !           268:                printf("%s: failed to initialize controller\n", self->dv_xname);
        !           269:                return;
        !           270:        }
        !           271: #endif
        !           272:
        !           273:        sc->sc_pciinten =
        !           274:            PCIINT_INA | PCIINT_SER | PCIINT_TPE | PCIINT_MPE |
        !           275:            PCIINT_MFE | PCIINT_PRA | PCIINT_PRD;
        !           276:
        !           277:        bus_space_write_4(iot, sc->sc_reg_ioh, PCICTL_PCIINTEN,
        !           278:            sc->sc_pciinten);
        !           279:
        !           280:        {
        !           281:                pcireg_t id_reg, class_reg;
        !           282:                char buf[1000];
        !           283:
        !           284:                id_reg = bus_space_read_4(iot, sc->sc_reg_ioh,
        !           285:                    PCI_ID_REG);
        !           286:                class_reg = bus_space_read_4(iot,
        !           287:                    sc->sc_reg_ioh, PCI_CLASS_REG);
        !           288:
        !           289:                pci_devinfo(id_reg, class_reg, 1, buf, sizeof(buf));
        !           290:                printf("%s: %s\n", self->dv_xname, buf);
        !           291:        }
        !           292:
        !           293: #if defined(PCI_NETBSD_CONFIGURE)
        !           294:        ioext = extent_create("pciio", 0x100, S3C2800_PCI_IOSPACE_SIZE - 0x100,
        !           295:            M_DEVBUF, NULL, 0, EX_NOWAIT);
        !           296:
        !           297:        memext = extent_create("pcimem", 0, S3C2800_PCI_MEMSPACE_SIZE,
        !           298:            M_DEVBUF, NULL, 0, EX_NOWAIT);
        !           299:
        !           300:        sspci_chipset.pc_conf_v = (void *) sc;
        !           301:        sspci_chipset.pc_intr_v = (void *) sc;
        !           302:
        !           303:        pci_configure_bus(&sspci_chipset, ioext, memext, NULL, 0,
        !           304:            arm_dcache_align);
        !           305:
        !           306:        extent_destroy(memext);
        !           307:        extent_destroy(ioext);
        !           308: #endif                         /* PCI_NETBSD_CONFIGURE */
        !           309:
        !           310:        /* initialize bus space tag */
        !           311:        sspci_io_tag = *iot;
        !           312:        sspci_io_tag.bs_cookie = (void *) S3C2800_PCI_IOSPACE_BASE;
        !           313:        sspci_io_tag.bs_map = sspci_bs_map;
        !           314:        sspci_mem_tag = *iot;
        !           315:        sspci_mem_tag.bs_cookie = (void *) S3C2800_PCI_MEMSPACE_BASE;
        !           316:        sspci_mem_tag.bs_map = sspci_bs_map;
        !           317:
        !           318:
        !           319:        /* Platform provides PCI DMA tag */
        !           320:        pci_dma_tag = s3c2800_pci_dma_init();
        !           321:
        !           322:        pci_pba.pba_pc = &sspci_chipset;
        !           323:        pci_pba.pba_iot = &sspci_io_tag;
        !           324:        pci_pba.pba_memt = &sspci_mem_tag;
        !           325:        pci_pba.pba_dmat = pci_dma_tag;
        !           326:        pci_pba.pba_dmat64 = NULL;
        !           327:        pci_pba.pba_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
        !           328:        pci_pba.pba_bus = 0;
        !           329:        pci_pba.pba_bridgetag = NULL;
        !           330:
        !           331:        config_found_ia(self, "pcibus", &pci_pba, pcibusprint);
        !           332:
        !           333:        return;
        !           334:
        !           335: #undef FAIL
        !           336: abort:
        !           337:        panic("%s: map failed (%s)",
        !           338:            self->dv_xname, error_on);
        !           339: }
        !           340:
        !           341:
        !           342: static int
        !           343: sspci_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flag,
        !           344:             bus_space_handle_t * bshp)
        !           345: {
        !           346:        bus_addr_t startpa, endpa;
        !           347:        vaddr_t va;
        !           348:
        !           349: #ifdef PCI_DEBUG
        !           350:        printf("sspci_bs_map: t=%p, addr=%lx, size=%lx, flag=%d\n",
        !           351:            t, bpa, size, flag);
        !           352: #endif
        !           353:
        !           354:        /* Round the allocation to page boundries */
        !           355:        startpa = trunc_page(bpa);
        !           356:        endpa = round_page(bpa + size);
        !           357:
        !           358:        /* Get some VM.  */
        !           359:        va = uvm_km_alloc(kernel_map, endpa - startpa, 0,
        !           360:            UVM_KMF_VAONLY | UVM_KMF_NOWAIT);
        !           361:        if (va == 0)
        !           362:                return ENOMEM;
        !           363:
        !           364:        /* Store the bus space handle */
        !           365:        *bshp = va + (bpa & PGOFSET);
        !           366:
        !           367:        /* Now map the pages */
        !           368:        /* The cookie is the physical base address for PCI I/O or memory area */
        !           369:        while (startpa < endpa) {
        !           370:                /* XXX pmap_kenter_pa maps pages cacheable -- not what we
        !           371:                 * want.  */
        !           372:                pmap_enter(pmap_kernel(), va, (bus_addr_t) t + startpa,
        !           373:                    VM_PROT_READ | VM_PROT_WRITE, 0);
        !           374:                va += PAGE_SIZE;
        !           375:                startpa += PAGE_SIZE;
        !           376:        }
        !           377:        pmap_update(pmap_kernel());
        !           378:
        !           379:        return 0;
        !           380: }
        !           381:
        !           382:
        !           383:
        !           384: void
        !           385: pci_conf_interrupt(pci_chipset_tag_t pc, int bus, int dev, int func,
        !           386:                   int swiz, int *iline)
        !           387: {
        !           388: #ifdef PCI_DEBUG
        !           389:        printf("pci_conf_interrupt(pc(%lx), bus(%d), dev(%d), func(%d), swiz(%d), *iline(%p)\n", (unsigned long) pc, bus, dev, func, swiz, iline);
        !           390: #endif
        !           391:        if (bus == 0) {
        !           392:                *iline = dev;
        !           393:        } else {
        !           394:                panic("pci_conf_interrupt: bus=%d: not yet implemented", bus);
        !           395:        }
        !           396: }
        !           397:
        !           398: void
        !           399: s3c2800_pci_attach_hook(struct device * parent, struct device * self,
        !           400:                        struct pcibus_attach_args * pba)
        !           401: {
        !           402:
        !           403:        /* Nothing to do. */
        !           404: #ifdef PCI_DEBUG
        !           405:        printf("s3c2800_pci_attach_hook()\n");
        !           406: #endif
        !           407: }
        !           408:
        !           409: int
        !           410: s3c2800_pci_bus_maxdevs(void *v, int busno)
        !           411: {
        !           412:
        !           413: #ifdef PCI_DEBUG
        !           414:        printf("s3c2800_pci_bus_maxdevs(v=%p, busno=%d)\n", v, busno);
        !           415: #endif
        !           416:        return (32);
        !           417: }
        !           418: pcitag_t
        !           419: s3c2800_pci_make_tag(void *v, int bus, int device, int function)
        !           420: {
        !           421:
        !           422:        return ((bus << BUSNO_SHIFT) | (device << DEVNO_SHIFT) |
        !           423:            (function << FUNNO_SHIFT));
        !           424: }
        !           425:
        !           426: void
        !           427: s3c2800_pci_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp)
        !           428: {
        !           429:        if (bp != NULL)
        !           430:                *bp = (tag >> BUSNO_SHIFT) & 0xff;
        !           431:        if (dp != NULL)
        !           432:                *dp = (tag >> DEVNO_SHIFT) & 0x1f;
        !           433:        if (fp != NULL)
        !           434:                *fp = (tag >> FUNNO_SHIFT) & 0x7;
        !           435: }
        !           436:
        !           437: static vaddr_t
        !           438: make_pci_conf_va(struct sspci_softc * sc, pcitag_t tag, int offset)
        !           439: {
        !           440:        if ((tag & BUSNO_MASK) == 0) {
        !           441:                /* configuration type 0 */
        !           442:                int devno = tag_to_devno(tag);
        !           443:
        !           444:                if (devno < BUS0_DEV_MIN || BUS0_DEV_MAX < devno)
        !           445:                        return 0;
        !           446:
        !           447:                return (vaddr_t) bus_space_vaddr(sc->sc_iot, sc->sc_conf0_ioh) +
        !           448:                    (tag & (DEVNO_MASK | FUNNO_MASK)) + offset;
        !           449:        } else {
        !           450:                /* XXX */
        !           451:                return (vaddr_t) - 1;   /* cause fault */
        !           452:        }
        !           453: }
        !           454:
        !           455:
        !           456: pcireg_t
        !           457: s3c2800_pci_conf_read(void *v, pcitag_t tag, int offset)
        !           458: {
        !           459:        struct sspci_softc *sc = v;
        !           460:        vaddr_t va = make_pci_conf_va(sc, tag, offset);
        !           461:        int s;
        !           462:        pcireg_t rv;
        !           463:
        !           464: #ifdef PCI_DEBUG
        !           465:        printf("s3c2800_pci_conf_read: base=%lx tag=%lx offset=%x\n",
        !           466:            sc->sc_conf0_ioh, tag, offset);
        !           467: #endif
        !           468:        if (va == 0)
        !           469:                return -1;
        !           470:
        !           471:        PCI_CONF_LOCK(s);
        !           472:
        !           473:        if (badaddr_read((void *) va, sizeof(rv), &rv)) {
        !           474: #if PCI_DEBUG
        !           475:                printf("conf_read: %lx bad address\n", va);
        !           476: #endif
        !           477:                rv = (pcireg_t) - 1;
        !           478:        }
        !           479:        PCI_CONF_UNLOCK(s);
        !           480:
        !           481:        return rv;
        !           482: }
        !           483:
        !           484: void
        !           485: s3c2800_pci_conf_write(void *v, pcitag_t tag, int offset, pcireg_t val)
        !           486: {
        !           487:        struct sspci_softc *sc = v;
        !           488:        vaddr_t va = make_pci_conf_va(sc, tag, offset);
        !           489:        u_int s;
        !           490:
        !           491: #ifdef PCI_DEBUG
        !           492:        printf("s3c2800_pci_conf_write: tag=%lx offset=%x -> va=%lx\n", tag, offset, va);
        !           493: #endif
        !           494:
        !           495:        PCI_CONF_LOCK(s);
        !           496:
        !           497:        *(pcireg_t *) va = val;
        !           498:
        !           499:        PCI_CONF_UNLOCK(s);
        !           500: }
        !           501:
        !           502: void *
        !           503: s3c2800_pci_intr_establish(void *pcv, pci_intr_handle_t ih, int level,
        !           504:                           int (*func) (void *), void *arg)
        !           505: {
        !           506:        struct sspci_softc *sc = pcv;
        !           507:        struct sspci_irq_handler *handler;
        !           508:        int s;
        !           509:
        !           510: #ifdef PCI_DEBUG
        !           511:        printf("s3c2800_pci_intr_establish(pcv=%p, ih=0x%lx, level=%d, "
        !           512:            "func=%p, arg=%p)\n", pcv, ih, level, func, arg);
        !           513: #endif
        !           514:
        !           515:        handler = malloc(sizeof *handler, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
        !           516:        if (handler == NULL)
        !           517:                panic("sspci_intr_establish: can't malloc handler info");
        !           518:
        !           519:        handler->func = func;
        !           520:        handler->arg = arg;
        !           521:        handler->level = level;
        !           522:
        !           523:        s = splhigh();
        !           524:        SLIST_INSERT_HEAD(&sc->sc_irq_handlers, handler, link);
        !           525:        splx(s);
        !           526:
        !           527:        return (handler);
        !           528: }
        !           529:
        !           530: void
        !           531: s3c2800_pci_intr_disestablish(void *pcv, void *cookie)
        !           532: {
        !           533:        struct sspci_softc *sc = pcv;
        !           534:        struct sspci_irq_handler *ih = cookie;
        !           535:        int s;
        !           536:
        !           537: #ifdef PCI_DEBUG
        !           538:        printf("s3c2800_pci_intr_disestablish(pcv=%p, cookie=%p)\n",
        !           539:            pcv, cookie);
        !           540: #endif
        !           541:
        !           542:        s = splhigh();
        !           543:        SLIST_REMOVE(&sc->sc_irq_handlers, ih, sspci_irq_handler, link);
        !           544:        splx(s);
        !           545: }
        !           546:
        !           547: int
        !           548: s3c2800_pci_intr_map(struct pci_attach_args * pa, pci_intr_handle_t * ihp)
        !           549: {
        !           550: #ifdef PCI_DEBUG
        !           551:        int pin = pa->pa_intrpin;
        !           552:        void *pcv = pa->pa_pc;
        !           553:        pcitag_t intrtag = pa->pa_intrtag;
        !           554:        int bus, device, function;
        !           555:
        !           556:        s3c2800_pci_decompose_tag(pcv, intrtag, &bus, &device, &function);
        !           557:        printf("s3c2800_pci_intr_map: pcv=%p, tag=%08lx pin=%d dev=%d\n",
        !           558:            pcv, intrtag, pin, device);
        !           559: #endif
        !           560:
        !           561:
        !           562:        /* S3C2800 has only one interrupt line for PCI */
        !           563:        *ihp = 0;
        !           564:        return 0;
        !           565: }
        !           566:
        !           567: const char *
        !           568: s3c2800_pci_intr_string(void *pcv, pci_intr_handle_t ih)
        !           569: {
        !           570:        /* We have only one interrupt source from PCI */
        !           571:        return "pciint";
        !           572: }
        !           573:
        !           574: const struct evcnt *
        !           575: s3c2800_pci_intr_evcnt(void *pcv, pci_intr_handle_t ih)
        !           576: {
        !           577:
        !           578:        /* XXX for now, no evcnt parent reported */
        !           579:        return NULL;
        !           580: }
        !           581: /*
        !           582:  * Initialize PCI controller
        !           583:  */
        !           584: int
        !           585: sspci_init_controller(struct sspci_softc * sc)
        !           586: {
        !           587:        bus_space_tag_t iot = sc->sc_iot;
        !           588:        bus_space_handle_t ioh = sc->sc_reg_ioh;
        !           589:
        !           590:        /* disable PCI command */
        !           591:        bus_space_write_4(iot, ioh, PCI_COMMAND_STATUS_REG,
        !           592:            0xffff0000);
        !           593:
        !           594:        /* latency=0x10, cacheline=8 */
        !           595:        bus_space_write_4(iot, ioh, PCI_BHLC_REG,
        !           596:            PCI_BHLC_CODE(0, 0, 0, 0x10, 8));
        !           597:
        !           598:        bus_space_write_4(iot, ioh, PCI_INTERRUPT_REG,
        !           599:            PCI_INTERRUPT_CODE(0, 0, 0, 0));
        !           600:
        !           601:
        !           602:
        !           603: #if 1
        !           604:        bus_space_write_4(iot, ioh, PCI_MAPREG_START,
        !           605:            PCI_MAPREG_MEM_TYPE_32BIT | 0x80000000);
        !           606:        /* Cover all DBANKs with BAR0 */
        !           607:        bus_space_write_4(iot, ioh, PCICTL_PCIBAM0, 0xf8000000);
        !           608:        bus_space_write_4(iot, ioh, PCICTL_PCIBATPA0, S3C2800_DBANK0_START);
        !           609: #else
        !           610:        bus_space_write_4(iot, ioh, PCI_MAPREG_START,
        !           611:            PCI_MAPREG_MEM_TYPE_32BIT | 0xf0000000);
        !           612:        bus_space_write_4(iot, ioh, PCI_MAPREG_START + 4,
        !           613:            PCI_MAPREG_MEM_TYPE_32BIT | 0x80000000);
        !           614:
        !           615:        bus_space_write_4(iot, ioh, PCICTL_PCIBAM0, 0xffff0000);
        !           616:        bus_space_write_4(iot, ioh, PCICTL_PCIBATPA0, 0xffff0000);
        !           617:        bus_space_write_4(iot, ioh, PCICTL_PCIBAM1, 0xf1000000);
        !           618:        bus_space_write_4(iot, ioh, PCICTL_PCIBATPA1, S3C2800_DBANK0_START);
        !           619: #endif
        !           620:
        !           621:        bus_space_write_4(iot, ioh, PCI_COMMAND_STATUS_REG,
        !           622:            PCI_STATUS_PARITY_DETECT |
        !           623:            PCI_STATUS_SPECIAL_ERROR |
        !           624:            PCI_STATUS_MASTER_ABORT |
        !           625:            PCI_STATUS_MASTER_TARGET_ABORT |
        !           626:            PCI_STATUS_TARGET_TARGET_ABORT |
        !           627:            PCI_STATUS_DEVSEL_MEDIUM |
        !           628:            PCI_STATUS_PARITY_ERROR |
        !           629:            PCI_STATUS_BACKTOBACK_SUPPORT |
        !           630:            PCI_STATUS_CAPLIST_SUPPORT |
        !           631:            PCI_COMMAND_MASTER_ENABLE |
        !           632:            PCI_COMMAND_MEM_ENABLE |
        !           633:            PCI_COMMAND_IO_ENABLE);
        !           634:
        !           635:        bus_space_write_4(iot, ioh, PCICTL_PCICON,
        !           636:            PCICON_ARB | PCICON_HST);
        !           637:
        !           638:        bus_space_write_4(iot, ioh, PCICTL_PCISET, 0);
        !           639:        /* clear all interrupts */
        !           640:        bus_space_write_4(iot, ioh, PCICTL_PCIINTST, 0xffffffff);
        !           641:        bus_space_write_4(iot, ioh, PCICTL_PCIINTEN, 0);
        !           642:
        !           643:        bus_space_write_4(iot, ioh, PCICTL_PCICON,
        !           644:            PCICON_RDY | PCICON_CFD | PCICON_ATS |
        !           645:            PCICON_ARB | PCICON_HST);
        !           646:
        !           647:
        !           648: #ifdef PCI_DEBUG
        !           649:        {
        !           650:                pcireg_t reg;
        !           651:                int i;
        !           652:
        !           653:                for (i = 0; i <= 0x40; i += sizeof(pcireg_t)) {
        !           654:                        reg = bus_space_read_4(iot, ioh, i);
        !           655:                        printf("%03x: %08x\n", i, reg);
        !           656:                }
        !           657:                for (i = 0x100; i <= 0x154; i += sizeof(pcireg_t)) {
        !           658:                        reg = bus_space_read_4(iot, ioh, i);
        !           659:                        printf("%03x: %08x\n", i, reg);
        !           660:                }
        !           661:        }
        !           662: #endif
        !           663:        return 0;
        !           664: }
        !           665:
        !           666:
        !           667: static const char *pci_abnormal_error_name[] = {
        !           668:        "PCI reset deasserted",
        !           669:        "PCI reset asserted",
        !           670:        "PCI master detected fatal error",
        !           671:        "PCI master detected parity error",
        !           672:        "PCI target detected parity error",
        !           673:        "PCI SERR# asserted",
        !           674: };
        !           675:
        !           676: static int
        !           677: sspci_intr(void *arg)
        !           678: {
        !           679:        struct sspci_softc *sc = arg;
        !           680:        int s;
        !           681:        bus_space_tag_t iot = sc->sc_iot;
        !           682:        bus_space_handle_t ioh = sc->sc_reg_ioh;
        !           683:        uint32_t interrupts, errors;
        !           684:
        !           685:        interrupts = bus_space_read_4(iot, ioh, PCICTL_PCIINTST);
        !           686:
        !           687:        if (interrupts & PCIINT_INA) {
        !           688:                s = splhigh();
        !           689:                softintr_schedule(sc->sc_softinterrupt);
        !           690:
        !           691:                /* mask INTA itnerrupt until softinterrupt is handled */
        !           692:                sc->sc_pciinten &= ~PCIINT_INA;
        !           693:                bus_space_write_4(iot, ioh, PCICTL_PCIINTEN,
        !           694:                    sc->sc_pciinten);
        !           695:
        !           696:                /* acknowledge INTA interrupt */
        !           697:                bus_space_write_4(iot, ioh, PCICTL_PCIINTST, PCIINT_INA);
        !           698:
        !           699:                splx(s);
        !           700:
        !           701:                interrupts &= ~PCIINT_INA;
        !           702:
        !           703:        }
        !           704:        errors = interrupts & (PCIINT_SER | PCIINT_TPE | PCIINT_MPE |
        !           705:            PCIINT_MFE | PCIINT_PRA | PCIINT_PRD);
        !           706:        if (errors) {
        !           707:                int i;
        !           708:
        !           709:                for (i = 0; errors; ++i) {
        !           710:                        if ((errors & (1 << i)) == 0)
        !           711:                                continue;
        !           712:
        !           713:                        printf("%s: %s\n", sc->sc_dev.dv_xname,
        !           714:                            pci_abnormal_error_name[i > 4 ? 5 : i]);
        !           715:
        !           716:                        errors &= ~(1 << i);
        !           717:                }
        !           718:                /* acknowledge interrupts */
        !           719:                bus_space_write_4(iot, ioh, PCICTL_PCIINTST, interrupts);
        !           720:        }
        !           721:        return 0;
        !           722: }
        !           723:
        !           724: static void
        !           725: sspci_softintr(void *arg)
        !           726: {
        !           727:        struct sspci_softc *sc = arg;
        !           728:        struct sspci_irq_handler *ih;
        !           729:        int s;
        !           730:
        !           731:
        !           732:        SLIST_FOREACH(ih, &(sc->sc_irq_handlers), link) {
        !           733:                s = _splraise(ih->level);
        !           734:                ih->func(ih->arg);
        !           735:                splx(s);
        !           736:        }
        !           737:
        !           738:        /* unmask INTA interrupt */
        !           739:        s = splhigh();
        !           740:        sc->sc_pciinten |= PCIINT_INA;
        !           741:        bus_space_write_4(sc->sc_iot, sc->sc_reg_ioh, PCICTL_PCIINTEN,
        !           742:            sc->sc_pciinten);
        !           743:        splx(s);
        !           744: }

CVSweb