1 /* $OpenBSD: xhci_acpi.c,v 1.1 2018/07/02 11:23:19 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2018 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 22 #include <machine/bus.h> 23 #include <machine/intr.h> 24 25 #include <dev/acpi/acpireg.h> 26 #include <dev/acpi/acpivar.h> 27 #include <dev/acpi/acpidev.h> 28 #include <dev/acpi/amltypes.h> 29 #include <dev/acpi/dsdt.h> 30 31 #include <dev/usb/usb.h> 32 #include <dev/usb/usbdi.h> 33 #include <dev/usb/usbdivar.h> 34 #include <dev/usb/usb_mem.h> 35 36 #include <dev/usb/xhcireg.h> 37 #include <dev/usb/xhcivar.h> 38 39 struct xhci_acpi_softc { 40 struct xhci_softc sc; 41 struct acpi_softc *sc_acpi; 42 struct aml_node *sc_node; 43 44 bus_addr_t sc_addr; 45 bus_size_t sc_size; 46 47 int sc_irq; 48 int sc_irq_flags; 49 void *sc_ih; 50 }; 51 52 int xhci_acpi_match(struct device *, void *, void *); 53 void xhci_acpi_attach(struct device *, struct device *, void *); 54 55 struct cfattach xhci_acpi_ca = { 56 sizeof(struct xhci_acpi_softc), xhci_acpi_match, xhci_acpi_attach 57 }; 58 59 const char *xhci_hids[] = { 60 "PNP0D10", 61 NULL 62 }; 63 64 int xhci_acpi_parse_resources(int, union acpi_resource *, void *); 65 66 int 67 xhci_acpi_match(struct device *parent, void *match, void *aux) 68 { 69 struct acpi_attach_args *aaa = aux; 70 struct cfdata *cf = match; 71 72 return acpi_matchhids(aaa, xhci_hids, cf->cf_driver->cd_name); 73 } 74 75 void 76 xhci_acpi_attach(struct device *parent, struct device *self, void *aux) 77 { 78 struct xhci_acpi_softc *sc = (struct xhci_acpi_softc *)self; 79 struct acpi_attach_args *aaa = aux; 80 struct aml_value res; 81 int error; 82 83 sc->sc_acpi = (struct acpi_softc *)parent; 84 sc->sc_node = aaa->aaa_node; 85 printf(" %s", sc->sc_node->name); 86 87 if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) { 88 printf(": can't find registers\n"); 89 return; 90 } 91 92 aml_parse_resource(&res, xhci_acpi_parse_resources, sc); 93 printf(" addr 0x%lx/0x%lx", sc->sc_addr, sc->sc_size); 94 if (sc->sc_addr == 0 || sc->sc_size == 0) { 95 printf("\n"); 96 return; 97 } 98 99 printf(" irq %d", sc->sc_irq); 100 101 sc->sc.iot = aaa->aaa_memt; 102 sc->sc.sc_size = sc->sc_size; 103 sc->sc.sc_bus.dmatag = aaa->aaa_dmat; 104 105 if (bus_space_map(sc->sc.iot, sc->sc_addr, sc->sc_size, 0, 106 &sc->sc.ioh)) { 107 printf(": can't map registers\n"); 108 return; 109 } 110 111 sc->sc_ih = acpi_intr_establish(sc->sc_irq, sc->sc_irq_flags, IPL_USB, 112 xhci_intr, sc, sc->sc.sc_bus.bdev.dv_xname); 113 if (sc->sc_ih == NULL) { 114 printf(": can't establish interrupt\n"); 115 goto unmap; 116 } 117 118 strlcpy(sc->sc.sc_vendor, "Generic", sizeof(sc->sc.sc_vendor)); 119 if ((error = xhci_init(&sc->sc)) != 0) { 120 printf("%s: init failed, error=%d\n", 121 sc->sc.sc_bus.bdev.dv_xname, error); 122 goto disestablish_ret; 123 } 124 125 /* Attach usb device. */ 126 config_found(self, &sc->sc.sc_bus, usbctlprint); 127 128 /* Now that the stack is ready, config' the HC and enable interrupts. */ 129 xhci_config(&sc->sc); 130 131 return; 132 133 disestablish_ret: 134 #ifdef notyet 135 acpi_intr_disestablish(sc->sc_ih); 136 #endif 137 unmap: 138 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 139 return; 140 } 141 142 int 143 xhci_acpi_parse_resources(int crsidx, union acpi_resource *crs, void *arg) 144 { 145 struct xhci_acpi_softc *sc = arg; 146 int type = AML_CRSTYPE(crs); 147 148 switch (type) { 149 case LR_MEM32FIXED: 150 /* XHCI registers are specified by the first resource. */ 151 if (sc->sc_size == 0) { 152 sc->sc_addr = crs->lr_m32fixed._bas; 153 sc->sc_size = crs->lr_m32fixed._len; 154 } 155 break; 156 case LR_EXTIRQ: 157 sc->sc_irq = crs->lr_extirq.irq[0]; 158 sc->sc_irq_flags = crs->lr_extirq.flags; 159 break; 160 } 161 162 return 0; 163 } 164