1 /* $OpenBSD: sdhc_acpi.c,v 1.18 2021/03/08 13:48:56 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 struct sdhc_acpi_softc { 33 struct sdhc_softc sc; 34 struct acpi_softc *sc_acpi; 35 struct aml_node *sc_node; 36 37 bus_space_tag_t sc_memt; 38 bus_space_handle_t sc_memh; 39 void *sc_ih; 40 41 struct aml_node *sc_gpio_int_node; 42 struct aml_node *sc_gpio_io_node; 43 uint16_t sc_gpio_int_pin; 44 uint16_t sc_gpio_int_flags; 45 uint16_t sc_gpio_io_pin; 46 47 struct sdhc_host *sc_host; 48 }; 49 50 int sdhc_acpi_match(struct device *, void *, void *); 51 void sdhc_acpi_attach(struct device *, struct device *, void *); 52 53 struct cfattach sdhc_acpi_ca = { 54 sizeof(struct sdhc_acpi_softc), sdhc_acpi_match, sdhc_acpi_attach 55 }; 56 57 const char *sdhc_hids[] = { 58 "PNP0D40", 59 "80860F14", 60 "BCM2847", /* Raspberry Pi3/4 "arasan" controller */ 61 "BRCME88C", /* Raspberry Pi4 "emmc2" controller */ 62 "INT33BB", 63 "PNP0FFF", 64 NULL 65 }; 66 67 int sdhc_acpi_parse_resources(int, union acpi_resource *, void *); 68 int sdhc_acpi_card_detect_nonremovable(struct sdhc_softc *); 69 int sdhc_acpi_card_detect_gpio(struct sdhc_softc *); 70 int sdhc_acpi_card_detect_intr(void *); 71 void sdhc_acpi_power_on(struct sdhc_acpi_softc *, struct aml_node *); 72 void sdhc_acpi_explore(struct sdhc_acpi_softc *); 73 74 int 75 sdhc_acpi_match(struct device *parent, void *match, void *aux) 76 { 77 struct acpi_attach_args *aaa = aux; 78 struct cfdata *cf = match; 79 80 return acpi_matchhids(aaa, sdhc_hids, cf->cf_driver->cd_name); 81 } 82 83 void 84 sdhc_acpi_attach(struct device *parent, struct device *self, void *aux) 85 { 86 struct sdhc_acpi_softc *sc = (struct sdhc_acpi_softc *)self; 87 struct acpi_attach_args *aaa = aux; 88 struct aml_value res; 89 uint32_t cap, capmask; 90 91 sc->sc_acpi = (struct acpi_softc *)parent; 92 sc->sc_node = aaa->aaa_node; 93 printf(" %s", sc->sc_node->name); 94 95 if (aaa->aaa_naddr < 1) { 96 printf(": no registers\n"); 97 return; 98 } 99 100 if (aaa->aaa_nirq < 1) { 101 printf(": no interrupt\n"); 102 return; 103 } 104 105 if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) { 106 printf(": can't find registers\n"); 107 return; 108 } 109 110 aml_parse_resource(&res, sdhc_acpi_parse_resources, sc); 111 112 printf(" addr 0x%llx/0x%llx", aaa->aaa_addr[0], aaa->aaa_size[0]); 113 printf(" irq %d", aaa->aaa_irq[0]); 114 115 sc->sc_memt = aaa->aaa_bst[0]; 116 if (bus_space_map(sc->sc_memt, aaa->aaa_addr[0], aaa->aaa_size[0], 117 0, &sc->sc_memh)) { 118 printf(": can't map registers\n"); 119 return; 120 } 121 122 sc->sc_ih = acpi_intr_establish(aaa->aaa_irq[0], aaa->aaa_irq_flags[0], 123 IPL_BIO, sdhc_intr, sc, sc->sc.sc_dev.dv_xname); 124 if (sc->sc_ih == NULL) { 125 printf(": can't establish interrupt\n"); 126 return; 127 } 128 129 if (sc->sc_gpio_io_node && sc->sc_gpio_io_node->gpio) { 130 sc->sc.sc_card_detect = sdhc_acpi_card_detect_gpio; 131 printf(", gpio"); 132 } 133 134 printf("\n"); 135 136 if (sc->sc_gpio_int_node && sc->sc_gpio_int_node->gpio) { 137 struct acpi_gpio *gpio = sc->sc_gpio_int_node->gpio; 138 139 gpio->intr_establish(gpio->cookie, sc->sc_gpio_int_pin, 140 sc->sc_gpio_int_flags, sdhc_acpi_card_detect_intr, sc); 141 } 142 143 sdhc_acpi_power_on(sc, sc->sc_node); 144 sdhc_acpi_explore(sc); 145 146 cap = acpi_getpropint(sc->sc_node, "sdhci-caps", 0); 147 capmask = acpi_getpropint(sc->sc_node, "sdhci-caps-mask", 0); 148 if (capmask != 0) { 149 cap = bus_space_read_4(sc->sc_memt, sc->sc_memh, 150 SDHC_CAPABILITIES); 151 cap &= ~capmask; 152 } 153 154 /* Raspberry Pi4 "emmc2" controller. */ 155 if (strcmp(aaa->aaa_dev, "BRCME88C") == 0) 156 sc->sc.sc_flags |= SDHC_F_NOPWR0; 157 158 sc->sc.sc_host = &sc->sc_host; 159 sc->sc.sc_dmat = aaa->aaa_dmat; 160 sc->sc.sc_clkbase = acpi_getpropint(sc->sc_node, 161 "clock-frequency", 0) / 1000; 162 sdhc_host_found(&sc->sc, sc->sc_memt, sc->sc_memh, 163 aaa->aaa_size[0], 1, cap); 164 } 165 166 int 167 sdhc_acpi_parse_resources(int crsidx, union acpi_resource *crs, void *arg) 168 { 169 struct sdhc_acpi_softc *sc = arg; 170 int type = AML_CRSTYPE(crs); 171 struct aml_node *node; 172 uint16_t pin; 173 174 switch (type) { 175 case LR_GPIO: 176 node = aml_searchname(sc->sc_node, (char *)&crs->pad[crs->lr_gpio.res_off]); 177 pin = *(uint16_t *)&crs->pad[crs->lr_gpio.pin_off]; 178 if (crs->lr_gpio.type == LR_GPIO_INT) { 179 sc->sc_gpio_int_node = node; 180 sc->sc_gpio_int_pin = pin; 181 sc->sc_gpio_int_flags = crs->lr_gpio.tflags; 182 } else if (crs->lr_gpio.type == LR_GPIO_IO) { 183 sc->sc_gpio_io_node = node; 184 sc->sc_gpio_io_pin = pin; 185 } 186 break; 187 } 188 189 return 0; 190 } 191 192 int 193 sdhc_acpi_card_detect_nonremovable(struct sdhc_softc *ssc) 194 { 195 return 1; 196 } 197 198 int 199 sdhc_acpi_card_detect_gpio(struct sdhc_softc *ssc) 200 { 201 struct sdhc_acpi_softc *sc = (struct sdhc_acpi_softc *)ssc; 202 struct acpi_gpio *gpio = sc->sc_gpio_io_node->gpio; 203 uint16_t pin = sc->sc_gpio_io_pin; 204 205 /* Card detect GPIO signal is active-low. */ 206 return !gpio->read_pin(gpio->cookie, pin); 207 } 208 209 int 210 sdhc_acpi_card_detect_intr(void *arg) 211 { 212 struct sdhc_acpi_softc *sc = arg; 213 214 sdhc_needs_discover(&sc->sc); 215 216 return (1); 217 } 218 219 void 220 sdhc_acpi_power_on(struct sdhc_acpi_softc *sc, struct aml_node *node) 221 { 222 node = aml_searchname(node, "_PS0"); 223 if (node && aml_evalnode(sc->sc_acpi, node, 0, NULL, NULL)) 224 printf("%s: _PS0 failed\n", sc->sc.sc_dev.dv_xname); 225 } 226 227 int 228 sdhc_acpi_do_explore(struct aml_node *node, void *arg) 229 { 230 struct sdhc_acpi_softc *sc = arg; 231 int64_t sta, rmv; 232 233 /* We're only interested in our children. */ 234 if (node == sc->sc_node) 235 return 0; 236 237 /* Only consider devices that are actually present. */ 238 if (node->value == NULL || 239 node->value->type != AML_OBJTYPE_DEVICE) 240 return 1; 241 if (aml_evalinteger(sc->sc_acpi, node, "_STA", 0, NULL, &sta)) 242 sta = STA_PRESENT | STA_ENABLED | STA_DEV_OK | 0x1000; 243 if ((sta & STA_PRESENT) == 0) 244 return 1; 245 246 acpi_attach_deps(sc->sc_acpi, node); 247 248 /* Override card detect if we have non-removable devices. */ 249 if (aml_evalinteger(sc->sc_acpi, node, "_RMV", 0, NULL, &rmv)) 250 rmv = 1; 251 if (rmv == 0) { 252 sc->sc.sc_flags |= SDHC_F_NONREMOVABLE; 253 if (sc->sc.sc_card_detect == NULL) { 254 sc->sc.sc_card_detect = 255 sdhc_acpi_card_detect_nonremovable; 256 } 257 } 258 259 sdhc_acpi_power_on(sc, node); 260 261 return 1; 262 } 263 264 void 265 sdhc_acpi_explore(struct sdhc_acpi_softc *sc) 266 { 267 aml_walknodes(sc->sc_node, AML_WALK_PRE, sdhc_acpi_do_explore, sc); 268 } 269