xref: /netbsd-src/sys/dev/acpi/acpica/OsdHardware.c (revision 76c7fc5f6b13ed0b1508e6b313e88e59977ed78e)
1 /*	$NetBSD: OsdHardware.c,v 1.11 2019/02/15 20:48:57 kamil 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.11 2019/02/15 20:48:57 kamil Exp $");
48 
49 #include <sys/param.h>
50 #include <sys/device.h>
51 
52 #include <dev/acpi/acpica.h>
53 #include <dev/acpi/acpivar.h>
54 #include <dev/acpi/acpi_pci.h>
55 
56 #include <machine/acpi_machdep.h>
57 
58 /*
59  * ACPICA doesn't provide much in the way of letting us know which
60  * hardware resources it wants to use.  We therefore have to resort
61  * to calling machinde-dependent code to do the access for us.
62  */
63 
64 /*
65  * AcpiOsReadPort:
66  *
67  *	Read a value from an input port.
68  */
69 ACPI_STATUS
70 AcpiOsReadPort(ACPI_IO_ADDRESS Address, UINT32 *Value, UINT32 Width)
71 {
72 
73 	switch (Width) {
74 	case 8:
75 		*Value = acpi_md_OsIn8(Address);
76 		break;
77 
78 	case 16:
79 		*Value = acpi_md_OsIn16(Address);
80 		break;
81 
82 	case 32:
83 		*Value = acpi_md_OsIn32(Address);
84 		break;
85 
86 	default:
87 		return AE_BAD_PARAMETER;
88 	}
89 
90 	return AE_OK;
91 }
92 
93 /*
94  * AcpiOsWritePort:
95  *
96  *	Write a value to an output port.
97  */
98 ACPI_STATUS
99 AcpiOsWritePort(ACPI_IO_ADDRESS Address, UINT32 Value, UINT32 Width)
100 {
101 
102 	switch (Width) {
103 	case 8:
104 		acpi_md_OsOut8(Address, Value);
105 		break;
106 
107 	case 16:
108 		acpi_md_OsOut16(Address, Value);
109 		break;
110 
111 	case 32:
112 		acpi_md_OsOut32(Address, Value);
113 		break;
114 
115 	default:
116 		return AE_BAD_PARAMETER;
117 	}
118 
119 	return AE_OK;
120 }
121 
122 /*
123  * AcpiOsReadMemory:
124  *
125  *	Read a value from a memory location.
126  */
127 ACPI_STATUS
128 AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address, UINT64 *Value, UINT32 Width)
129 {
130 	void *LogicalAddress;
131 	ACPI_STATUS rv = AE_OK;
132 
133 	LogicalAddress = AcpiOsMapMemory(Address, Width / 8);
134 	if (LogicalAddress == NULL)
135 		return AE_NOT_EXIST;
136 
137 	switch (Width) {
138 	case 8:
139 		*Value = *(volatile uint8_t *) LogicalAddress;
140 		break;
141 
142 	case 16:
143 		*Value = *(volatile uint16_t *) LogicalAddress;
144 		break;
145 
146 	case 32:
147 		*Value = *(volatile uint32_t *) LogicalAddress;
148 		break;
149 
150 	case 64:
151 		*Value = *(volatile uint64_t *) LogicalAddress;
152 		break;
153 
154 	default:
155 		rv = AE_BAD_PARAMETER;
156 	}
157 
158 	AcpiOsUnmapMemory(LogicalAddress, Width / 8);
159 
160 	return rv;
161 }
162 
163 /*
164  * AcpiOsWriteMemory:
165  *
166  *	Write a value to a memory location.
167  */
168 ACPI_STATUS
169 AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address, UINT64 Value, UINT32 Width)
170 {
171 	void *LogicalAddress;
172 	ACPI_STATUS rv = AE_OK;
173 
174 	LogicalAddress = AcpiOsMapMemory(Address, Width / 8);
175 	if (LogicalAddress == NULL)
176 		return AE_NOT_FOUND;
177 
178 	switch (Width) {
179 	case 8:
180 		*(volatile uint8_t *) LogicalAddress = Value;
181 		break;
182 
183 	case 16:
184 		*(volatile uint16_t *) LogicalAddress = Value;
185 		break;
186 
187 	case 32:
188 		*(volatile uint32_t *) LogicalAddress = Value;
189 		break;
190 
191 	case 64:
192 		*(volatile uint64_t *) LogicalAddress = Value;
193 		break;
194 
195 	default:
196 		rv = AE_BAD_PARAMETER;
197 	}
198 
199 	AcpiOsUnmapMemory(LogicalAddress, Width / 8);
200 
201 	return rv;
202 }
203 
204 /*
205  * AcpiOsReadPciConfiguration:
206  *
207  *	Read a value from a PCI configuration register.
208  */
209 ACPI_STATUS
210 AcpiOsReadPciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register, UINT64 *Value,
211     UINT32 Width)
212 {
213 	pcitag_t tag;
214 	pcireg_t tmp;
215 	pci_chipset_tag_t pc = acpi_softc ? acpi_softc->sc_pc : NULL;
216 
217 	/* XXX Need to deal with "segment" ("hose" in Alpha terminology). */
218 
219 	if (PciId->Bus >= 256 || PciId->Device >= 32 || PciId->Function >= 8)
220 		return AE_BAD_PARAMETER;
221 
222 	tag = pci_make_tag(pc, PciId->Bus, PciId->Device, PciId->Function);
223 	tmp = pci_conf_read(pc, tag, Register & ~3);
224 
225 	switch (Width) {
226 	case 8:
227 		*(uint8_t *) Value = (tmp >> ((Register & 3) * 8)) & 0xff;
228 		break;
229 
230 	case 16:
231 		*(uint16_t *) Value = (tmp >> ((Register & 3) * 8)) & 0xffff;
232 		break;
233 
234 	case 32:
235 		*(uint32_t *) Value = tmp;
236 		break;
237 
238 	default:
239 		return AE_BAD_PARAMETER;
240 	}
241 
242 	return AE_OK;
243 }
244 
245 /*
246  * AcpiOsWritePciConfiguration:
247  *
248  *	Write a value to a PCI configuration register.
249  */
250 ACPI_STATUS
251 AcpiOsWritePciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register,
252     ACPI_INTEGER Value, UINT32 Width)
253 {
254 	pcitag_t tag;
255 	pcireg_t tmp;
256 	pci_chipset_tag_t pc = acpi_softc ? acpi_softc->sc_pc : NULL;
257 
258 	/* XXX Need to deal with "segment" ("hose" in Alpha terminology). */
259 
260 	tag = pci_make_tag(pc, PciId->Bus, PciId->Device, PciId->Function);
261 
262 	switch (Width) {
263 	case 8:
264 		tmp = pci_conf_read(pc, tag, Register & ~3);
265 		tmp &= ~(0xffu << ((Register & 3) * 8));
266 		tmp |= (Value << ((Register & 3) * 8));
267 		break;
268 
269 	case 16:
270 		tmp = pci_conf_read(pc, tag, Register & ~3);
271 		tmp &= ~(0xffffu << ((Register & 3) * 8));
272 		tmp |= (Value << ((Register & 3) * 8));
273 		break;
274 
275 	case 32:
276 		tmp = Value;
277 		break;
278 
279 	default:
280 		return AE_BAD_PARAMETER;
281 	}
282 
283 	pci_conf_write(pc, tag, Register & ~3, tmp);
284 
285 	return AE_OK;
286 }
287