1 /* $NetBSD: OsdHardware.c,v 1.15 2024/06/23 15:21:52 andvar Exp $ */
2
3 /*
4 * Copyright 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 /*
39 * OS Services Layer
40 *
41 * 6.7: Address Space Access: Port Input/Output
42 * 6.8: Address Space Access: Memory and Memory Mapped I/O
43 * 6.9: Address Space Access: PCI Configuration Space
44 */
45
46 #include <sys/cdefs.h>
47 __KERNEL_RCSID(0, "$NetBSD: OsdHardware.c,v 1.15 2024/06/23 15:21:52 andvar Exp $");
48
49 #include "pci.h"
50
51 #include <sys/param.h>
52 #include <sys/device.h>
53
54 #include <dev/acpi/acpica.h>
55 #include <dev/acpi/acpivar.h>
56 #include <dev/acpi/acpi_pci.h>
57
58 #include <machine/acpi_machdep.h>
59
60 /*
61 * ACPICA doesn't provide much in the way of letting us know which
62 * hardware resources it wants to use. We therefore have to resort
63 * to calling machine-dependent code to do the access for us.
64 */
65
66 /*
67 * AcpiOsReadPort:
68 *
69 * Read a value from an input port.
70 */
71 ACPI_STATUS
AcpiOsReadPort(ACPI_IO_ADDRESS Address,UINT32 * Value,UINT32 Width)72 AcpiOsReadPort(ACPI_IO_ADDRESS Address, UINT32 *Value, UINT32 Width)
73 {
74
75 switch (Width) {
76 case 8:
77 *Value = acpi_md_OsIn8(Address);
78 break;
79
80 case 16:
81 *Value = acpi_md_OsIn16(Address);
82 break;
83
84 case 32:
85 *Value = acpi_md_OsIn32(Address);
86 break;
87
88 default:
89 return AE_BAD_PARAMETER;
90 }
91
92 return AE_OK;
93 }
94
95 /*
96 * AcpiOsWritePort:
97 *
98 * Write a value to an output port.
99 */
100 ACPI_STATUS
AcpiOsWritePort(ACPI_IO_ADDRESS Address,UINT32 Value,UINT32 Width)101 AcpiOsWritePort(ACPI_IO_ADDRESS Address, UINT32 Value, UINT32 Width)
102 {
103
104 switch (Width) {
105 case 8:
106 acpi_md_OsOut8(Address, Value);
107 break;
108
109 case 16:
110 acpi_md_OsOut16(Address, Value);
111 break;
112
113 case 32:
114 acpi_md_OsOut32(Address, Value);
115 break;
116
117 default:
118 return AE_BAD_PARAMETER;
119 }
120
121 return AE_OK;
122 }
123
124 /*
125 * AcpiOsReadMemory:
126 *
127 * Read a value from a memory location.
128 */
129 ACPI_STATUS
AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address,UINT64 * Value,UINT32 Width)130 AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address, UINT64 *Value, UINT32 Width)
131 {
132 void *LogicalAddress;
133 ACPI_STATUS rv = AE_OK;
134
135 LogicalAddress = AcpiOsMapMemory(Address, Width / 8);
136 if (LogicalAddress == NULL)
137 return AE_NOT_EXIST;
138
139 switch (Width) {
140 case 8:
141 *Value = *(volatile uint8_t *) LogicalAddress;
142 break;
143
144 case 16:
145 *Value = *(volatile uint16_t *) LogicalAddress;
146 break;
147
148 case 32:
149 *Value = *(volatile uint32_t *) LogicalAddress;
150 break;
151
152 case 64:
153 *Value = *(volatile uint64_t *) LogicalAddress;
154 break;
155
156 default:
157 rv = AE_BAD_PARAMETER;
158 }
159
160 AcpiOsUnmapMemory(LogicalAddress, Width / 8);
161
162 return rv;
163 }
164
165 /*
166 * AcpiOsWriteMemory:
167 *
168 * Write a value to a memory location.
169 */
170 ACPI_STATUS
AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address,UINT64 Value,UINT32 Width)171 AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address, UINT64 Value, UINT32 Width)
172 {
173 void *LogicalAddress;
174 ACPI_STATUS rv = AE_OK;
175
176 LogicalAddress = AcpiOsMapMemory(Address, Width / 8);
177 if (LogicalAddress == NULL)
178 return AE_NOT_FOUND;
179
180 switch (Width) {
181 case 8:
182 *(volatile uint8_t *) LogicalAddress = Value;
183 break;
184
185 case 16:
186 *(volatile uint16_t *) LogicalAddress = Value;
187 break;
188
189 case 32:
190 *(volatile uint32_t *) LogicalAddress = Value;
191 break;
192
193 case 64:
194 *(volatile uint64_t *) LogicalAddress = Value;
195 break;
196
197 default:
198 rv = AE_BAD_PARAMETER;
199 }
200
201 AcpiOsUnmapMemory(LogicalAddress, Width / 8);
202
203 return rv;
204 }
205
206 /*
207 * AcpiOsReadPciConfiguration:
208 *
209 * Read a value from a PCI configuration register.
210 */
211 ACPI_STATUS
AcpiOsReadPciConfiguration(ACPI_PCI_ID * PciId,UINT32 Register,UINT64 * Value,UINT32 Width)212 AcpiOsReadPciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register, UINT64 *Value,
213 UINT32 Width)
214 {
215 #if NPCI > 0
216 pci_chipset_tag_t pc;
217 pcitag_t tag;
218 pcireg_t tmp;
219
220 if (PciId->Bus >= 256 || PciId->Device >= 32 || PciId->Function >= 8)
221 return AE_BAD_PARAMETER;
222
223 pc = acpi_pcidev_get_tag(PciId->Segment, PciId->Bus, PciId->Device, PciId->Function);
224
225 tag = pci_make_tag(pc, PciId->Bus, PciId->Device, PciId->Function);
226 tmp = pci_conf_read(pc, tag, Register & ~3);
227
228 switch (Width) {
229 case 8:
230 *Value = (tmp >> ((Register & 3) * 8)) & 0xff;
231 break;
232
233 case 16:
234 *Value = (tmp >> ((Register & 3) * 8)) & 0xffff;
235 break;
236
237 case 32:
238 *Value = tmp;
239 break;
240
241 default:
242 return AE_BAD_PARAMETER;
243 }
244
245 return AE_OK;
246 #else
247 return AE_BAD_PARAMETER;
248 #endif
249 }
250
251 /*
252 * AcpiOsWritePciConfiguration:
253 *
254 * Write a value to a PCI configuration register.
255 */
256 ACPI_STATUS
AcpiOsWritePciConfiguration(ACPI_PCI_ID * PciId,UINT32 Register,ACPI_INTEGER Value,UINT32 Width)257 AcpiOsWritePciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register,
258 ACPI_INTEGER Value, UINT32 Width)
259 {
260 #if NPCI > 0
261 pci_chipset_tag_t pc;
262 pcitag_t tag;
263 pcireg_t tmp;
264
265 pc = acpi_pcidev_get_tag(PciId->Segment, PciId->Bus, PciId->Device, PciId->Function);
266 tag = pci_make_tag(pc, PciId->Bus, PciId->Device, PciId->Function);
267
268 switch (Width) {
269 case 8:
270 tmp = pci_conf_read(pc, tag, Register & ~3);
271 tmp &= ~(0xffu << ((Register & 3) * 8));
272 tmp |= (Value << ((Register & 3) * 8));
273 break;
274
275 case 16:
276 tmp = pci_conf_read(pc, tag, Register & ~3);
277 tmp &= ~(0xffffu << ((Register & 3) * 8));
278 tmp |= (Value << ((Register & 3) * 8));
279 break;
280
281 case 32:
282 tmp = Value;
283 break;
284
285 default:
286 return AE_BAD_PARAMETER;
287 }
288
289 pci_conf_write(pc, tag, Register & ~3, tmp);
290
291 return AE_OK;
292 #else
293 return AE_BAD_PARAMETER;
294 #endif
295 }
296