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