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 */
71ACPI_STATUS
72AcpiOsReadPort(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 */
100ACPI_STATUS
101AcpiOsWritePort(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 */
129ACPI_STATUS
130AcpiOsReadMemory(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 */
170ACPI_STATUS
171AcpiOsWriteMemory(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 */
211ACPI_STATUS
212AcpiOsReadPciConfiguration(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 */
256ACPI_STATUS
257AcpiOsWritePciConfiguration(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