1 1.6 thorpej /* $NetBSD: ipmi_acpi.c,v 1.6 2021/08/07 16:19:09 thorpej Exp $ */ 2 1.1 mlelstv 3 1.1 mlelstv /*- 4 1.1 mlelstv * Copyright (c) 2018 The NetBSD Foundation, Inc. 5 1.1 mlelstv * All rights reserved. 6 1.1 mlelstv * 7 1.1 mlelstv * This code is derived from software contributed to The NetBSD Foundation 8 1.1 mlelstv * by Michael van Elst 9 1.1 mlelstv * 10 1.1 mlelstv * Redistribution and use in source and binary forms, with or without 11 1.1 mlelstv * modification, are permitted provided that the following conditions 12 1.1 mlelstv * are met: 13 1.1 mlelstv * 1. Redistributions of source code must retain the above copyright 14 1.1 mlelstv * notice, this list of conditions and the following disclaimer. 15 1.1 mlelstv * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 mlelstv * notice, this list of conditions and the following disclaimer in the 17 1.1 mlelstv * documentation and/or other materials provided with the distribution. 18 1.1 mlelstv * 19 1.1 mlelstv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 mlelstv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 mlelstv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 mlelstv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 mlelstv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 mlelstv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 mlelstv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 mlelstv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 mlelstv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 mlelstv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 mlelstv * POSSIBILITY OF SUCH DAMAGE. 30 1.1 mlelstv */ 31 1.1 mlelstv 32 1.1 mlelstv #include <sys/cdefs.h> 33 1.6 thorpej __KERNEL_RCSID(0, "$NetBSD: ipmi_acpi.c,v 1.6 2021/08/07 16:19:09 thorpej Exp $"); 34 1.1 mlelstv 35 1.1 mlelstv #include <sys/param.h> 36 1.1 mlelstv #include <sys/device.h> 37 1.1 mlelstv #include <sys/module.h> 38 1.1 mlelstv #include <sys/systm.h> 39 1.1 mlelstv 40 1.1 mlelstv #include <dev/acpi/acpireg.h> 41 1.1 mlelstv #include <dev/acpi/acpivar.h> 42 1.1 mlelstv 43 1.1 mlelstv #include <dev/ipmivar.h> 44 1.1 mlelstv 45 1.1 mlelstv #define _COMPONENT ACPI_RESOURCE_COMPONENT 46 1.1 mlelstv ACPI_MODULE_NAME ("ipmi_acpi") 47 1.1 mlelstv 48 1.1 mlelstv typedef struct ipmi_acpi_softc { 49 1.1 mlelstv device_t sc_dev; 50 1.1 mlelstv bool sc_init; 51 1.1 mlelstv } ipmi_acpi_softc_t; 52 1.1 mlelstv 53 1.1 mlelstv static int ipmi_acpi_match(device_t, cfdata_t, void *); 54 1.1 mlelstv static void ipmi_acpi_attach(device_t, device_t, void *); 55 1.1 mlelstv static int ipmi_acpi_detach(device_t, int); 56 1.1 mlelstv 57 1.1 mlelstv CFATTACH_DECL3_NEW(ipmi_acpi, sizeof(ipmi_acpi_softc_t), 58 1.1 mlelstv ipmi_acpi_match, ipmi_acpi_attach, ipmi_acpi_detach, NULL, NULL, NULL, 59 1.1 mlelstv DVF_DETACH_SHUTDOWN); 60 1.1 mlelstv 61 1.4 thorpej static const struct device_compatible_entry compat_data[] = { 62 1.4 thorpej { .compat = "IPI0001" }, 63 1.4 thorpej DEVICE_COMPAT_EOL 64 1.1 mlelstv }; 65 1.1 mlelstv 66 1.1 mlelstv static int 67 1.1 mlelstv ipmi_acpi_match(device_t parent, cfdata_t match, void *opaque) 68 1.1 mlelstv { 69 1.1 mlelstv struct acpi_attach_args *aa = (struct acpi_attach_args *)opaque; 70 1.1 mlelstv 71 1.4 thorpej return acpi_compatible_match(aa, compat_data); 72 1.1 mlelstv } 73 1.1 mlelstv 74 1.1 mlelstv static void 75 1.1 mlelstv ipmi_acpi_attach(device_t parent, device_t self, void *opaque) 76 1.1 mlelstv { 77 1.1 mlelstv ipmi_acpi_softc_t *sc = device_private(self); 78 1.1 mlelstv struct acpi_attach_args *aa = (struct acpi_attach_args *)opaque; 79 1.1 mlelstv ACPI_STATUS rv; 80 1.1 mlelstv ACPI_INTEGER itype, ivers, adr; 81 1.1 mlelstv struct acpi_resources res; 82 1.1 mlelstv struct acpi_io *io; 83 1.1 mlelstv struct acpi_mem *mem; 84 1.1 mlelstv #if notyet 85 1.1 mlelstv struct acpi_irq *irq; 86 1.1 mlelstv #endif 87 1.1 mlelstv struct ipmi_attach_args IA, *ia = &IA; 88 1.1 mlelstv bus_addr_t reg2; 89 1.2 mlelstv uint16_t i2caddr; 90 1.1 mlelstv 91 1.1 mlelstv sc->sc_dev = self; 92 1.1 mlelstv 93 1.1 mlelstv aprint_naive("\n"); 94 1.1 mlelstv 95 1.1 mlelstv rv = acpi_eval_integer(aa->aa_node->ad_handle, "_IFT", &itype); 96 1.1 mlelstv if (ACPI_FAILURE(rv)) { 97 1.1 mlelstv aprint_error("no _IFT\n"); 98 1.1 mlelstv return; 99 1.1 mlelstv } 100 1.1 mlelstv 101 1.1 mlelstv rv = acpi_eval_integer(aa->aa_node->ad_handle, "_SRV", &ivers); 102 1.1 mlelstv if (ACPI_FAILURE(rv)) { 103 1.1 mlelstv aprint_error("no _SRV\n"); 104 1.1 mlelstv return; 105 1.1 mlelstv } 106 1.1 mlelstv 107 1.1 mlelstv switch (itype) { 108 1.1 mlelstv case IPMI_IF_KCS: 109 1.1 mlelstv case IPMI_IF_SMIC: 110 1.1 mlelstv case IPMI_IF_BT: 111 1.1 mlelstv rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS", 112 1.1 mlelstv &res, &acpi_resource_parse_ops_default); 113 1.1 mlelstv if (ACPI_FAILURE(rv)) { 114 1.1 mlelstv aprint_normal("\n"); 115 1.1 mlelstv aprint_error_dev(self, "no resources\n"); 116 1.1 mlelstv return; 117 1.1 mlelstv } 118 1.1 mlelstv 119 1.1 mlelstv io = acpi_res_io(&res, 0); 120 1.1 mlelstv mem = acpi_res_mem(&res, 0); 121 1.1 mlelstv if (io == NULL && mem == NULL) { 122 1.1 mlelstv aprint_error_dev(self, "no resources\n"); 123 1.1 mlelstv return; 124 1.1 mlelstv } 125 1.1 mlelstv 126 1.1 mlelstv #if notyet 127 1.1 mlelstv if ((irq = acpi_res_irq(&res, 0)) != NULL) { 128 1.1 mlelstv aprint_normal_dev(self, "IRQ %d type %d\n", 129 1.1 mlelstv irq->ar_irq, irq->ar_type); 130 1.1 mlelstv } else { 131 1.1 mlelstv aprint_error_dev(self, "no interrupt\n"); 132 1.1 mlelstv } 133 1.1 mlelstv #endif 134 1.1 mlelstv ia->iaa_iot = aa->aa_iot; 135 1.1 mlelstv ia->iaa_memt = aa->aa_memt; 136 1.1 mlelstv 137 1.1 mlelstv ia->iaa_if_type = itype; 138 1.1 mlelstv ia->iaa_if_rev = ivers; 139 1.1 mlelstv ia->iaa_if_iotype = io ? 'i' : 'm'; 140 1.1 mlelstv ia->iaa_if_iobase = io ? io->ar_base : mem->ar_base; 141 1.1 mlelstv ia->iaa_if_iospacing = 1; 142 1.1 mlelstv ia->iaa_if_irq = -1; 143 1.1 mlelstv ia->iaa_if_irqlvl = 0; 144 1.1 mlelstv 145 1.1 mlelstv reg2 = 0; 146 1.1 mlelstv if (io) { 147 1.1 mlelstv io = acpi_res_io(&res, 1); 148 1.1 mlelstv if (io != NULL) 149 1.1 mlelstv reg2 = (bus_addr_t)io->ar_base; 150 1.1 mlelstv } else { 151 1.1 mlelstv mem = acpi_res_mem(&res, 1); 152 1.1 mlelstv if (mem != NULL) 153 1.1 mlelstv reg2 = mem->ar_base; 154 1.1 mlelstv } 155 1.1 mlelstv 156 1.1 mlelstv if (reg2 > ia->iaa_if_iobase) 157 1.1 mlelstv ia->iaa_if_iospacing = reg2 - ia->iaa_if_iobase; 158 1.1 mlelstv 159 1.6 thorpej config_found(self, ia, NULL, CFARGS_NONE); 160 1.1 mlelstv 161 1.1 mlelstv break; 162 1.1 mlelstv case IPMI_IF_SSIF: 163 1.1 mlelstv rv = acpi_eval_integer(aa->aa_node->ad_handle, "_ADR", &adr); 164 1.1 mlelstv if (ACPI_FAILURE(rv)) { 165 1.1 mlelstv aprint_normal("\n"); 166 1.1 mlelstv aprint_error_dev(self, "no resources\n"); 167 1.1 mlelstv return; 168 1.1 mlelstv } 169 1.2 mlelstv if (adr > 65535) { 170 1.2 mlelstv aprint_normal("\n"); 171 1.2 mlelstv aprint_error_dev(self, "i2c address out of range\n"); 172 1.2 mlelstv return; 173 1.2 mlelstv } 174 1.2 mlelstv i2caddr = adr; 175 1.2 mlelstv 176 1.2 mlelstv aprint_normal(": i2c 0x%x\n", i2caddr); 177 1.1 mlelstv break; 178 1.1 mlelstv default: 179 1.1 mlelstv aprint_normal("\n"); 180 1.1 mlelstv aprint_error_dev(self, "unknown interface type\n"); 181 1.1 mlelstv return; 182 1.1 mlelstv } 183 1.1 mlelstv 184 1.1 mlelstv sc->sc_init = true; 185 1.1 mlelstv 186 1.1 mlelstv if (!pmf_device_register(self, NULL, NULL)) 187 1.1 mlelstv aprint_error_dev(self, "couldn't establish power handler\n"); 188 1.1 mlelstv } 189 1.1 mlelstv 190 1.1 mlelstv static int 191 1.1 mlelstv ipmi_acpi_detach(device_t self, int flags) 192 1.1 mlelstv { 193 1.1 mlelstv struct ipmi_acpi_softc *sc = device_private(self); 194 1.1 mlelstv int rc; 195 1.1 mlelstv 196 1.1 mlelstv if (!sc->sc_init) 197 1.1 mlelstv return 0; 198 1.1 mlelstv 199 1.1 mlelstv rc = config_detach_children(self, flags); 200 1.1 mlelstv if (rc) 201 1.1 mlelstv return rc; 202 1.1 mlelstv 203 1.1 mlelstv pmf_device_deregister(self); 204 1.1 mlelstv return 0; 205 1.1 mlelstv } 206