2 * Copyright (C) 2008-2010 Nathan Whitehorn
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/module.h>
33 #include <sys/kernel.h>
35 #include <dev/ofw/openfirm.h>
36 #include <dev/ofw/ofw_pci.h>
38 #include <dev/pci/pcivar.h>
39 #include <dev/pci/pcireg.h>
41 #include <machine/bus.h>
42 #include <machine/intr_machdep.h>
43 #include <machine/md_var.h>
44 #include <machine/openpicvar.h>
45 #include <machine/pio.h>
46 #include <machine/resource.h>
50 #include <dev/ofw/ofw_bus.h>
51 #include <dev/ofw/ofw_bus_subr.h>
60 * IBM CPC9X5 Hypertransport Device interface.
62 static int cpcht_probe(device_t);
63 static int cpcht_attach(device_t);
65 static void cpcht_configure_htbridge(device_t, phandle_t);
70 static int cpcht_read_ivar(device_t, device_t, int,
72 static struct resource *cpcht_alloc_resource(device_t bus, device_t child,
73 int type, int *rid, u_long start, u_long end,
74 u_long count, u_int flags);
75 static int cpcht_activate_resource(device_t bus, device_t child,
76 int type, int rid, struct resource *res);
77 static int cpcht_release_resource(device_t bus, device_t child,
78 int type, int rid, struct resource *res);
79 static int cpcht_deactivate_resource(device_t bus, device_t child,
80 int type, int rid, struct resource *res);
85 static int cpcht_maxslots(device_t);
86 static u_int32_t cpcht_read_config(device_t, u_int, u_int, u_int,
88 static void cpcht_write_config(device_t, u_int, u_int, u_int,
89 u_int, u_int32_t, int);
90 static int cpcht_route_interrupt(device_t bus, device_t dev,
97 static phandle_t cpcht_get_node(device_t bus, device_t child);
102 static device_method_t cpcht_methods[] = {
103 /* Device interface */
104 DEVMETHOD(device_probe, cpcht_probe),
105 DEVMETHOD(device_attach, cpcht_attach),
108 DEVMETHOD(bus_print_child, bus_generic_print_child),
109 DEVMETHOD(bus_read_ivar, cpcht_read_ivar),
110 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
111 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
112 DEVMETHOD(bus_alloc_resource, cpcht_alloc_resource),
113 DEVMETHOD(bus_release_resource, cpcht_release_resource),
114 DEVMETHOD(bus_activate_resource, cpcht_activate_resource),
115 DEVMETHOD(bus_deactivate_resource, cpcht_deactivate_resource),
118 DEVMETHOD(pcib_maxslots, cpcht_maxslots),
119 DEVMETHOD(pcib_read_config, cpcht_read_config),
120 DEVMETHOD(pcib_write_config, cpcht_write_config),
121 DEVMETHOD(pcib_route_interrupt, cpcht_route_interrupt),
123 /* ofw_bus interface */
124 DEVMETHOD(ofw_bus_get_node, cpcht_get_node),
132 vm_offset_t apple_eoi;
137 static struct cpcht_irq *cpcht_irqmap = NULL;
143 uint64_t sc_populated_slots;
144 struct rman sc_mem_rman;
146 struct cpcht_irq htirq_map[128];
149 static driver_t cpcht_driver = {
152 sizeof(struct cpcht_softc)
155 static devclass_t cpcht_devclass;
157 DRIVER_MODULE(cpcht, nexus, cpcht_driver, cpcht_devclass, 0, 0);
159 #define HTAPIC_REQUEST_EOI 0x20
160 #define HTAPIC_TRIGGER_LEVEL 0x02
161 #define HTAPIC_MASK 0x01
175 cpcht_probe(device_t dev)
177 const char *type, *compatible;
179 type = ofw_bus_get_type(dev);
180 compatible = ofw_bus_get_compat(dev);
182 if (type == NULL || compatible == NULL)
185 if (strcmp(type, "ht") != 0)
188 if (strcmp(compatible, "u3-ht") != 0)
192 device_set_desc(dev, "IBM CPC9X5 HyperTransport Tunnel");
197 cpcht_attach(device_t dev)
199 struct cpcht_softc *sc;
200 phandle_t node, child;
204 node = ofw_bus_get_node(dev);
205 sc = device_get_softc(dev);
207 if (OF_getprop(node, "reg", reg, sizeof(reg)) < 12)
212 sc->sc_populated_slots = 0;
213 sc->sc_data = (vm_offset_t)pmap_mapdev(reg[1], reg[2]);
215 sc->sc_mem_rman.rm_type = RMAN_ARRAY;
216 sc->sc_mem_rman.rm_descr = "CPCHT Device Memory";
217 error = rman_init(&sc->sc_mem_rman);
220 device_printf(dev, "rman_init() failed. error = %d\n", error);
225 * Set up the resource manager and the HT->MPIC mapping. For cpcht,
226 * the ranges are properties of the child bridges, and this is also
227 * where we get the HT interrupts properties.
230 bzero(sc->htirq_map, sizeof(sc->htirq_map));
231 for (child = OF_child(node); child != 0; child = OF_peer(child))
232 cpcht_configure_htbridge(dev, child);
234 /* Now make the mapping table available to the MPIC */
235 cpcht_irqmap = sc->htirq_map;
237 device_add_child(dev, "pci", device_get_unit(dev));
239 return (bus_generic_attach(dev));
243 cpcht_configure_htbridge(device_t dev, phandle_t child)
245 struct cpcht_softc *sc;
246 struct ofw_pci_register pcir;
247 struct cpcht_range ranges[6], *rp;
248 int nranges, ptr, nextptr;
253 sc = device_get_softc(dev);
254 if (OF_getprop(child, "reg", &pcir, sizeof(pcir)) == -1)
257 s = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi);
258 f = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi);
261 * Mark this slot is populated. The remote south bridge does
262 * not like us talking to unpopulated slots on the root bus.
264 sc->sc_populated_slots |= (1 << s);
267 * Next grab this child bus's bus ranges.
269 bzero(ranges, sizeof(ranges));
270 nranges = OF_getprop(child, "ranges", ranges, sizeof(ranges));
272 ranges[6].pci_hi = 0;
273 for (rp = ranges; rp->pci_hi != 0; rp++) {
274 switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
275 case OFW_PCI_PHYS_HI_SPACE_CONFIG:
277 case OFW_PCI_PHYS_HI_SPACE_IO:
278 case OFW_PCI_PHYS_HI_SPACE_MEM32:
279 rman_manage_region(&sc->sc_mem_rman, rp->pci_lo,
280 rp->pci_lo + rp->size_lo - 1);
282 case OFW_PCI_PHYS_HI_SPACE_MEM64:
283 panic("64-bit CPCHT reserved memory!");
289 * Next build up any HT->MPIC mappings for this sub-bus. One would
290 * naively hope that enabling, disabling, and EOIing interrupts would
291 * cause the appropriate HT bus transactions to that effect. This is
294 * Instead, we have to muck about on the HT peer's root PCI bridges,
295 * figure out what interrupts they send, enable them, and cache
296 * the location of their WaitForEOI registers so that we can
300 /* All the devices we are interested in have caps */
301 if (!(PCIB_READ_CONFIG(dev, 0, s, f, PCIR_STATUS, 2)
302 & PCIM_STATUS_CAPPRESENT))
305 nextptr = PCIB_READ_CONFIG(dev, 0, s, f, PCIR_CAP_PTR, 1);
306 while (nextptr != 0) {
308 nextptr = PCIB_READ_CONFIG(dev, 0, s, f,
309 ptr + PCICAP_NEXTPTR, 1);
311 /* Find the HT IRQ capabilities */
312 if (PCIB_READ_CONFIG(dev, 0, s, f,
313 ptr + PCICAP_ID, 1) != PCIY_HT)
316 val = PCIB_READ_CONFIG(dev, 0, s, f, ptr + PCIR_HT_COMMAND, 2);
317 if ((val & PCIM_HTCMD_CAP_MASK) != PCIM_HTCAP_INTERRUPT)
320 /* Ask for the IRQ count */
321 PCIB_WRITE_CONFIG(dev, 0, s, f, ptr + PCIR_HT_COMMAND, 0x1, 1);
322 nirq = PCIB_READ_CONFIG(dev, 0, s, f, ptr + 4, 4);
323 nirq = ((nirq >> 16) & 0xff) + 1;
325 device_printf(dev, "%d HT IRQs on device %d.%d\n", nirq, s, f);
327 for (i = 0; i < nirq; i++) {
328 PCIB_WRITE_CONFIG(dev, 0, s, f,
329 ptr + PCIR_HT_COMMAND, 0x10 + (i << 1), 1);
330 irq = PCIB_READ_CONFIG(dev, 0, s, f, ptr + 4, 4);
333 * Mask this interrupt for now.
335 PCIB_WRITE_CONFIG(dev, 0, s, f, ptr + 4,
336 irq | HTAPIC_MASK, 4);
337 irq = (irq >> 16) & 0xff;
339 sc->htirq_map[irq].ht_source = i;
340 sc->htirq_map[irq].ht_base = sc->sc_data +
341 (((((s & 0x1f) << 3) | (f & 0x07)) << 8) | (ptr));
343 PCIB_WRITE_CONFIG(dev, 0, s, f,
344 ptr + PCIR_HT_COMMAND, 0x11 + (i << 1), 1);
345 sc->htirq_map[irq].eoi_data =
346 PCIB_READ_CONFIG(dev, 0, s, f, ptr + 4, 4) |
350 * Apple uses a non-compliant IO/APIC that differs
351 * in how we signal EOIs. Check if this device was
352 * made by Apple, and act accordingly.
354 vend = PCIB_READ_CONFIG(dev, 0, s, f,
356 if ((vend & 0xffff) == 0x106b)
357 sc->htirq_map[irq].apple_eoi =
358 (sc->htirq_map[irq].ht_base - ptr) + 0x60;
364 cpcht_maxslots(device_t dev)
367 return (PCI_SLOTMAX);
371 cpcht_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
374 struct cpcht_softc *sc;
377 sc = device_get_softc(dev);
378 caoff = sc->sc_data +
379 (((((slot & 0x1f) << 3) | (func & 0x07)) << 8) | reg);
381 if (bus == 0 && (!(sc->sc_populated_slots & (1 << slot)) || func > 0))
385 caoff += 0x01000000UL + (bus << 16);
389 return (in8rb(caoff));
392 return (in16rb(caoff));
395 return (in32rb(caoff));
403 cpcht_write_config(device_t dev, u_int bus, u_int slot, u_int func,
404 u_int reg, u_int32_t val, int width)
406 struct cpcht_softc *sc;
409 sc = device_get_softc(dev);
410 caoff = sc->sc_data +
411 (((((slot & 0x1f) << 3) | (func & 0x07)) << 8) | reg);
413 if (bus == 0 && (!(sc->sc_populated_slots & (1 << slot)) || func > 0))
417 caoff += 0x01000000UL + (bus << 16);
433 cpcht_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
435 struct cpcht_softc *sc;
437 sc = device_get_softc(dev);
440 case PCIB_IVAR_DOMAIN:
441 *result = device_get_unit(dev);
444 *result = 0; /* Root bus */
452 cpcht_get_node(device_t bus, device_t dev)
454 struct cpcht_softc *sc;
456 sc = device_get_softc(bus);
457 /* We only have one child, the PCI bus, which needs our own node. */
458 return (sc->sc_node);
462 cpcht_route_interrupt(device_t bus, device_t dev, int pin)
467 static struct resource *
468 cpcht_alloc_resource(device_t bus, device_t child, int type, int *rid,
469 u_long start, u_long end, u_long count, u_int flags)
471 struct cpcht_softc *sc;
474 int needactivate, err;
476 needactivate = flags & RF_ACTIVE;
479 sc = device_get_softc(bus);
484 end = min(end, start + count);
488 rm = &sc->sc_mem_rman;
492 return (bus_alloc_resource(bus, type, rid, start, end, count,
496 device_printf(bus, "unknown resource request from %s\n",
497 device_get_nameunit(child));
501 rv = rman_reserve_resource(rm, start, end, count, flags, child);
503 device_printf(bus, "failed to reserve resource for %s\n",
504 device_get_nameunit(child));
508 rman_set_rid(rv, *rid);
511 if (bus_activate_resource(child, type, *rid, rv) != 0) {
513 "failed to activate resource for %s\n",
514 device_get_nameunit(child));
515 rman_release_resource(rv);
524 cpcht_activate_resource(device_t bus, device_t child, int type, int rid,
525 struct resource *res)
528 struct cpcht_softc *sc;
530 sc = device_get_softc(bus);
532 if (type == SYS_RES_IRQ)
533 return (bus_activate_resource(bus, type, rid, res));
535 if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
538 start = (vm_offset_t)rman_get_start(res);
541 printf("cpcht mapdev: start %zx, len %ld\n", start,
544 p = pmap_mapdev(start, (vm_size_t)rman_get_size(res));
547 rman_set_virtual(res, p);
548 rman_set_bustag(res, &bs_le_tag);
549 rman_set_bushandle(res, (u_long)p);
552 return (rman_activate_resource(res));
556 cpcht_release_resource(device_t bus, device_t child, int type, int rid,
557 struct resource *res)
560 if (rman_get_flags(res) & RF_ACTIVE) {
561 int error = bus_deactivate_resource(child, type, rid, res);
566 return (rman_release_resource(res));
570 cpcht_deactivate_resource(device_t bus, device_t child, int type, int rid,
571 struct resource *res)
575 * If this is a memory resource, unmap it.
577 if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
580 psize = rman_get_size(res);
581 pmap_unmapdev((vm_offset_t)rman_get_virtual(res), psize);
584 return (rman_deactivate_resource(res));
588 * Driver for the integrated MPIC on U3/U4 (CPC925/CPC945)
591 static int openpic_cpcht_probe(device_t);
592 static int openpic_cpcht_attach(device_t);
593 static void openpic_cpcht_config(device_t, u_int irq,
594 enum intr_trigger trig, enum intr_polarity pol);
595 static void openpic_cpcht_enable(device_t, u_int irq, u_int vector);
596 static void openpic_cpcht_unmask(device_t, u_int irq);
597 static void openpic_cpcht_eoi(device_t, u_int irq);
599 static device_method_t openpic_cpcht_methods[] = {
600 /* Device interface */
601 DEVMETHOD(device_probe, openpic_cpcht_probe),
602 DEVMETHOD(device_attach, openpic_cpcht_attach),
605 DEVMETHOD(pic_config, openpic_cpcht_config),
606 DEVMETHOD(pic_dispatch, openpic_dispatch),
607 DEVMETHOD(pic_enable, openpic_cpcht_enable),
608 DEVMETHOD(pic_eoi, openpic_cpcht_eoi),
609 DEVMETHOD(pic_ipi, openpic_ipi),
610 DEVMETHOD(pic_mask, openpic_mask),
611 DEVMETHOD(pic_unmask, openpic_cpcht_unmask),
616 struct openpic_cpcht_softc {
617 struct openpic_softc sc_openpic;
619 struct mtx sc_ht_mtx;
622 static driver_t openpic_cpcht_driver = {
624 openpic_cpcht_methods,
625 sizeof(struct openpic_cpcht_softc),
628 DRIVER_MODULE(openpic, unin, openpic_cpcht_driver, openpic_devclass, 0, 0);
631 openpic_cpcht_probe(device_t dev)
633 const char *type = ofw_bus_get_type(dev);
635 if (strcmp(type, "open-pic") != 0)
638 device_set_desc(dev, OPENPIC_DEVSTR);
643 openpic_cpcht_attach(device_t dev)
645 struct openpic_cpcht_softc *sc;
648 err = openpic_attach(dev);
653 * The HT APIC stuff is not thread-safe, so we need a mutex to
656 sc = device_get_softc(dev);
657 mtx_init(&sc->sc_ht_mtx, "htpic", NULL, MTX_SPIN);
660 * Interrupts 0-3 are internally sourced and are level triggered
661 * active low. Interrupts 4-123 are connected to a pulse generator
662 * and should be programmed as edge triggered low-to-high.
664 * IBM CPC945 Manual, Section 9.3.
667 for (irq = 0; irq < 4; irq++)
668 openpic_config(dev, irq, INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
669 for (irq = 4; irq < 124; irq++)
670 openpic_config(dev, irq, INTR_TRIGGER_EDGE, INTR_POLARITY_LOW);
676 openpic_cpcht_config(device_t dev, u_int irq, enum intr_trigger trig,
677 enum intr_polarity pol)
679 struct openpic_cpcht_softc *sc;
683 * The interrupt settings for the MPIC are completely determined
684 * by the internal wiring in the northbridge. Real changes to these
685 * settings need to be negotiated with the remote IO-APIC on the HT
689 sc = device_get_softc(dev);
691 if (cpcht_irqmap != NULL && irq < 128 &&
692 cpcht_irqmap[irq].ht_base > 0 && !cpcht_irqmap[irq].edge) {
693 mtx_lock_spin(&sc->sc_ht_mtx);
695 /* Program the data port */
696 out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND,
697 0x10 + (cpcht_irqmap[irq].ht_source << 1));
699 /* Grab the IRQ config register */
700 ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4);
702 /* Mask the IRQ while we fiddle settings */
703 out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq | HTAPIC_MASK);
705 /* Program the interrupt sense */
706 ht_irq &= ~(HTAPIC_TRIGGER_LEVEL | HTAPIC_REQUEST_EOI);
707 if (trig == INTR_TRIGGER_EDGE) {
708 cpcht_irqmap[irq].edge = 1;
710 cpcht_irqmap[irq].edge = 0;
711 ht_irq |= HTAPIC_TRIGGER_LEVEL | HTAPIC_REQUEST_EOI;
713 out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq);
715 mtx_unlock_spin(&sc->sc_ht_mtx);
720 openpic_cpcht_enable(device_t dev, u_int irq, u_int vec)
722 struct openpic_cpcht_softc *sc;
725 openpic_enable(dev, irq, vec);
727 sc = device_get_softc(dev);
729 if (cpcht_irqmap != NULL && irq < 128 &&
730 cpcht_irqmap[irq].ht_base > 0) {
731 mtx_lock_spin(&sc->sc_ht_mtx);
733 /* Program the data port */
734 out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND,
735 0x10 + (cpcht_irqmap[irq].ht_source << 1));
737 /* Unmask the interrupt */
738 ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4);
739 ht_irq &= ~HTAPIC_MASK;
740 out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq);
742 mtx_unlock_spin(&sc->sc_ht_mtx);
745 openpic_cpcht_eoi(dev, irq);
749 openpic_cpcht_unmask(device_t dev, u_int irq)
751 struct openpic_cpcht_softc *sc;
754 openpic_unmask(dev, irq);
756 sc = device_get_softc(dev);
758 if (cpcht_irqmap != NULL && irq < 128 &&
759 cpcht_irqmap[irq].ht_base > 0) {
760 mtx_lock_spin(&sc->sc_ht_mtx);
762 /* Program the data port */
763 out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND,
764 0x10 + (cpcht_irqmap[irq].ht_source << 1));
766 /* Unmask the interrupt */
767 ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4);
768 ht_irq &= ~HTAPIC_MASK;
769 out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq);
771 mtx_unlock_spin(&sc->sc_ht_mtx);
774 openpic_cpcht_eoi(dev, irq);
778 openpic_cpcht_eoi(device_t dev, u_int irq)
780 struct openpic_cpcht_softc *sc;
786 sc = device_get_softc(dev);
788 if (cpcht_irqmap != NULL && irq < 128 &&
789 cpcht_irqmap[irq].ht_base > 0 && !cpcht_irqmap[irq].edge) {
790 /* If this is an HT IRQ, acknowledge it at the remote APIC */
792 if (cpcht_irqmap[irq].apple_eoi) {
793 off = (cpcht_irqmap[irq].ht_source >> 3) & ~3;
794 mask = 1 << (cpcht_irqmap[irq].ht_source & 0x1f);
795 out32rb(cpcht_irqmap[irq].apple_eoi + off, mask);
797 mtx_lock_spin(&sc->sc_ht_mtx);
799 out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND,
800 0x11 + (cpcht_irqmap[irq].ht_source << 1));
801 out32rb(cpcht_irqmap[irq].ht_base + 4,
802 cpcht_irqmap[irq].eoi_data);
804 mtx_unlock_spin(&sc->sc_ht_mtx);
808 openpic_eoi(dev, irq);