ipmi_acpi.c revision 1.6 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