Annotation of sys/arch/arm/s3c2xx0/s3c2800_pci.c, Revision 1.1.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