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