1 /* $OpenBSD: sdhc_acpi.c,v 1.8 2016/04/30 11:32:23 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2016 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/malloc.h> 20 #include <sys/systm.h> 21 22 #include <dev/acpi/acpireg.h> 23 #include <dev/acpi/acpivar.h> 24 #include <dev/acpi/acpidev.h> 25 #include <dev/acpi/amltypes.h> 26 #include <dev/acpi/dsdt.h> 27 #undef DEVNAME 28 #include <dev/sdmmc/sdhcreg.h> 29 #include <dev/sdmmc/sdhcvar.h> 30 #include <dev/sdmmc/sdmmcvar.h> 31 32 extern struct bus_dma_tag pci_bus_dma_tag; 33 34 struct sdhc_acpi_softc { 35 struct sdhc_softc sc; 36 struct acpi_softc *sc_acpi; 37 struct aml_node *sc_node; 38 39 bus_space_tag_t sc_memt; 40 bus_space_handle_t sc_memh; 41 bus_addr_t sc_addr; 42 bus_size_t sc_size; 43 44 int sc_irq; 45 int sc_irq_flags; 46 void *sc_ih; 47 48 struct aml_node *sc_gpio_int_node; 49 struct aml_node *sc_gpio_io_node; 50 uint16_t sc_gpio_int_pin; 51 uint16_t sc_gpio_int_flags; 52 uint16_t sc_gpio_io_pin; 53 54 struct sdhc_host *sc_host; 55 }; 56 57 int sdhc_acpi_match(struct device *, void *, void *); 58 void sdhc_acpi_attach(struct device *, struct device *, void *); 59 60 struct cfattach sdhc_acpi_ca = { 61 sizeof(struct sdhc_acpi_softc), sdhc_acpi_match, sdhc_acpi_attach 62 }; 63 64 const char *sdhc_hids[] = { 65 "PNP0D40", 66 "INT33BB", 67 "80860F14", 68 "PNP0FFF", 69 NULL 70 }; 71 72 int sdhc_acpi_parse_resources(union acpi_resource *, void *); 73 int sdhc_acpi_card_detect(struct sdhc_softc *); 74 int sdhc_acpi_card_detect_intr(void *); 75 76 int 77 sdhc_acpi_match(struct device *parent, void *match, void *aux) 78 { 79 struct acpi_attach_args *aaa = aux; 80 struct cfdata *cf = match; 81 82 return acpi_matchhids(aaa, sdhc_hids, cf->cf_driver->cd_name); 83 } 84 85 void 86 sdhc_acpi_attach(struct device *parent, struct device *self, void *aux) 87 { 88 struct acpi_attach_args *aaa = aux; 89 struct sdhc_acpi_softc *sc = (struct sdhc_acpi_softc *)self; 90 struct aml_value res; 91 92 sc->sc_acpi = (struct acpi_softc *)parent; 93 sc->sc_node = aaa->aaa_node; 94 printf(": %s", sc->sc_node->name); 95 96 if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) { 97 printf(", can't find registers\n"); 98 return; 99 } 100 101 aml_parse_resource(&res, sdhc_acpi_parse_resources, sc); 102 printf(" addr 0x%lx/0x%lx", sc->sc_addr, sc->sc_size); 103 if (sc->sc_addr == 0 || sc->sc_size == 0) { 104 printf("\n"); 105 return; 106 } 107 108 printf(" irq %d", sc->sc_irq); 109 110 sc->sc_memt = aaa->aaa_memt; 111 if (bus_space_map(sc->sc_memt, sc->sc_addr, sc->sc_size, 0, 112 &sc->sc_memh)) { 113 printf(", can't map registers\n"); 114 return; 115 } 116 117 sc->sc_ih = acpi_intr_establish(sc->sc_irq, sc->sc_irq_flags, IPL_BIO, 118 sdhc_intr, sc, sc->sc.sc_dev.dv_xname); 119 if (sc->sc_ih == NULL) { 120 printf(", can't establish interrupt\n"); 121 return; 122 } 123 124 if (sc->sc_gpio_io_node && sc->sc_gpio_io_node->gpio) { 125 sc->sc.sc_card_detect = sdhc_acpi_card_detect; 126 printf(", gpio"); 127 } 128 129 if (sc->sc_gpio_int_node && sc->sc_gpio_int_node->gpio) { 130 struct acpi_gpio *gpio = sc->sc_gpio_int_node->gpio; 131 132 gpio->intr_establish(gpio->cookie, sc->sc_gpio_int_pin, 133 sc->sc_gpio_int_flags, sdhc_acpi_card_detect_intr, sc); 134 } 135 136 printf("\n"); 137 138 sc->sc.sc_host = &sc->sc_host; 139 sc->sc.sc_dmat = &pci_bus_dma_tag; 140 sdhc_host_found(&sc->sc, sc->sc_memt, sc->sc_memh, sc->sc_size, 1, 0); 141 } 142 143 int 144 sdhc_acpi_parse_resources(union acpi_resource *crs, void *arg) 145 { 146 struct sdhc_acpi_softc *sc = arg; 147 int type = AML_CRSTYPE(crs); 148 struct aml_node *node; 149 uint16_t pin; 150 151 switch (type) { 152 case LR_MEM32FIXED: 153 sc->sc_addr = crs->lr_m32fixed._bas; 154 sc->sc_size = crs->lr_m32fixed._len; 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 case LR_GPIO: 161 node = aml_searchname(sc->sc_node, (char *)&crs->pad[crs->lr_gpio.res_off]); 162 pin = *(uint16_t *)&crs->pad[crs->lr_gpio.pin_off]; 163 if (crs->lr_gpio.type == LR_GPIO_INT) { 164 sc->sc_gpio_int_node = node; 165 sc->sc_gpio_int_pin = pin; 166 sc->sc_gpio_int_flags = crs->lr_gpio.tflags; 167 } else if (crs->lr_gpio.type == LR_GPIO_IO) { 168 sc->sc_gpio_io_node = node; 169 sc->sc_gpio_io_pin = pin; 170 } 171 break; 172 } 173 174 return 0; 175 } 176 177 int 178 sdhc_acpi_card_detect(struct sdhc_softc *ssc) 179 { 180 struct sdhc_acpi_softc *sc = (struct sdhc_acpi_softc *)ssc; 181 struct acpi_gpio *gpio = sc->sc_gpio_io_node->gpio; 182 uint16_t pin = sc->sc_gpio_io_pin; 183 184 /* Card detect GPIO signal is active-low. */ 185 return !gpio->read_pin(gpio->cookie, pin); 186 } 187 188 int 189 sdhc_acpi_card_detect_intr(void *arg) 190 { 191 struct sdhc_acpi_softc *sc = arg; 192 193 sdhc_needs_discover(&sc->sc); 194 195 return (1); 196 } 197