xref: /netbsd-src/sys/dev/acpi/acpica/OsdHardware.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /*	$NetBSD: OsdHardware.c,v 1.4 2007/12/12 23:33:22 jmcneill 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.4 2007/12/12 23:33:22 jmcneill 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 
55 #include <machine/acpi_machdep.h>
56 
57 /*
58  * ACPICA doesn't provide much in the way of letting us know which
59  * hardware resources it wants to use.  We therefore have to resort
60  * to calling machinde-dependent code to do the access for us.
61  */
62 
63 /*
64  * AcpiOsReadPort:
65  *
66  *	Read a value from an input port.
67  */
68 ACPI_STATUS
69 AcpiOsReadPort(ACPI_IO_ADDRESS Address, UINT32 *Value, UINT32 Width)
70 {
71 
72 	switch (Width) {
73 	case 8:
74 		*Value = acpi_md_OsIn8(Address);
75 		break;
76 
77 	case 16:
78 		*Value = acpi_md_OsIn16(Address);
79 		break;
80 
81 	case 32:
82 		*Value = acpi_md_OsIn32(Address);
83 		break;
84 
85 	default:
86 		return AE_BAD_PARAMETER;
87 	}
88 
89 	return AE_OK;
90 }
91 
92 /*
93  * AcpiOsWritePort:
94  *
95  *	Write a value to an output port.
96  */
97 ACPI_STATUS
98 AcpiOsWritePort(ACPI_IO_ADDRESS Address, UINT32 Value, UINT32 Width)
99 {
100 
101 	switch (Width) {
102 	case 8:
103 		acpi_md_OsOut8(Address, Value);
104 		break;
105 
106 	case 16:
107 		acpi_md_OsOut16(Address, Value);
108 		break;
109 
110 	case 32:
111 		acpi_md_OsOut32(Address, Value);
112 		break;
113 
114 	default:
115 		return AE_BAD_PARAMETER;
116 	}
117 
118 	return AE_OK;
119 }
120 
121 /*
122  * AcpiOsReadMemory:
123  *
124  *	Read a value from a memory location.
125  */
126 ACPI_STATUS
127 AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address, UINT32 *Value, UINT32 Width)
128 {
129 	void *LogicalAddress;
130 	ACPI_STATUS rv;
131 
132 	LogicalAddress = AcpiOsMapMemory(Address, Width / 8);
133 	if (LogicalAddress == NULL)
134 		return AE_NOT_EXIST;
135 
136 	switch (Width) {
137 	case 8:
138 		*Value = *(volatile uint8_t *) LogicalAddress;
139 		break;
140 
141 	case 16:
142 		*Value = *(volatile uint16_t *) LogicalAddress;
143 		break;
144 
145 	case 32:
146 		*Value = *(volatile uint32_t *) LogicalAddress;
147 		break;
148 
149 	default:
150 		rv = AE_BAD_PARAMETER;
151 	}
152 
153 	AcpiOsUnmapMemory(LogicalAddress, Width / 8);
154 
155 	return rv;
156 }
157 
158 /*
159  * AcpiOsWriteMemory:
160  *
161  *	Write a value to a memory location.
162  */
163 ACPI_STATUS
164 AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address, UINT32 Value, UINT32 Width)
165 {
166 	void *LogicalAddress;
167 	ACPI_STATUS rv;
168 
169 	LogicalAddress = AcpiOsMapMemory(Address, Width / 8);
170 	if (LogicalAddress == NULL)
171 		return AE_NOT_FOUND;
172 
173 	switch (Width) {
174 	case 8:
175 		*(volatile uint8_t *) LogicalAddress = Value;
176 		break;
177 
178 	case 16:
179 		*(volatile uint16_t *) LogicalAddress = Value;
180 		break;
181 
182 	case 32:
183 		*(volatile uint32_t *) LogicalAddress = Value;
184 		break;
185 
186 	default:
187 		rv = AE_BAD_PARAMETER;
188 	}
189 
190 	AcpiOsUnmapMemory(LogicalAddress, Width / 8);
191 
192 	return rv;
193 }
194 
195 /*
196  * AcpiOsReadPciConfiguration:
197  *
198  *	Read a value from a PCI configuration register.
199  */
200 ACPI_STATUS
201 AcpiOsReadPciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register, void *Value,
202     UINT32 Width)
203 {
204 	pcitag_t tag;
205 	pcireg_t tmp;
206 
207 	/* XXX Need to deal with "segment" ("hose" in Alpha terminology). */
208 
209 	if (PciId->Bus >= 256 || PciId->Device >= 32 || PciId->Function >= 8)
210 		return AE_BAD_PARAMETER;
211 
212 	tag = pci_make_tag(acpi_softc->sc_pc, PciId->Bus, PciId->Device,
213 	    PciId->Function);
214 	tmp = pci_conf_read(acpi_softc->sc_pc, tag, Register & ~3);
215 
216 	switch (Width) {
217 	case 8:
218 		*(uint8_t *) Value = (tmp >> ((Register & 3) * 8)) & 0xff;
219 		break;
220 
221 	case 16:
222 		*(uint16_t *) Value = (tmp >> ((Register & 3) * 8)) & 0xffff;
223 		break;
224 
225 	case 32:
226 		*(uint32_t *) Value = tmp;
227 		break;
228 
229 	default:
230 		return AE_BAD_PARAMETER;
231 	}
232 
233 	return AE_OK;
234 }
235 
236 /*
237  * AcpiOsWritePciConfiguration:
238  *
239  *	Write a value to a PCI configuration register.
240  */
241 ACPI_STATUS
242 AcpiOsWritePciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register,
243     ACPI_INTEGER Value, UINT32 Width)
244 {
245 	pcitag_t tag;
246 	pcireg_t tmp;
247 
248 	/* XXX Need to deal with "segment" ("hose" in Alpha terminology). */
249 
250 	tag = pci_make_tag(acpi_softc->sc_pc, PciId->Bus, PciId->Device,
251 	    PciId->Function);
252 
253 	switch (Width) {
254 	case 8:
255 		tmp = pci_conf_read(acpi_softc->sc_pc, tag, Register & ~3);
256 		tmp &= ~(0xff << ((Register & 3) * 8));
257 		tmp |= (Value << ((Register & 3) * 8));
258 		break;
259 
260 	case 16:
261 		tmp = pci_conf_read(acpi_softc->sc_pc, tag, Register & ~3);
262 		tmp &= ~(0xffff << ((Register & 3) * 8));
263 		tmp |= (Value << ((Register & 3) * 8));
264 		break;
265 
266 	case 32:
267 		tmp = Value;
268 		break;
269 
270 	default:
271 		return AE_BAD_PARAMETER;
272 	}
273 
274 	pci_conf_write(acpi_softc->sc_pc, tag, Register & ~3, tmp);
275 
276 	return AE_OK;
277 }
278 
279 /* get PCI bus# from root bridge recursively */
280 static int
281 get_bus_number(
282     ACPI_HANDLE        rhandle,
283     ACPI_HANDLE        chandle,
284     ACPI_PCI_ID        **PciId)
285 {
286 	ACPI_HANDLE handle;
287 	ACPI_STATUS rv;
288 	ACPI_OBJECT_TYPE type;
289 	ACPI_PCI_ID *id;
290 	ACPI_INTEGER v;
291 	int bus;
292 
293 	id = *PciId;
294 
295 	rv = AcpiGetParent(chandle, &handle);
296 	if (ACPI_FAILURE(rv))
297 		return 0;
298 
299 	/*
300 	 * When handle == rhandle, we have valid PciId->Bus
301 	 * which was obtained from _BBN in evrgnini.c
302 	 * so we don't have to reevaluate _BBN.
303 	 */
304 	if (handle != rhandle) {
305 		bus = get_bus_number(rhandle, handle, PciId);
306 
307 		rv = AcpiGetType(handle, &type);
308 		if (ACPI_FAILURE(rv) || type != ACPI_TYPE_DEVICE)
309 			return bus;
310 
311 		rv = acpi_eval_integer(handle, METHOD_NAME__ADR, &v);
312 
313 		if (ACPI_FAILURE(rv))
314 			return bus;
315 
316 		id->Bus = bus;
317 		id->Device = ACPI_HIWORD((ACPI_INTEGER)v);
318 		id->Function = ACPI_LOWORD((ACPI_INTEGER)v);
319 
320 		/* read HDR_TYPE register */
321 		rv = AcpiOsReadPciConfiguration(id, 0x0e, &v, 8);
322 		if (ACPI_SUCCESS(rv) &&
323 			/* mask multifunction bit & check bridge type */
324 			((v & 0x7f) == 1 || (v & 0x7f) == 2)) {
325 			/* read SECONDARY_BUS register */
326 			rv = AcpiOsReadPciConfiguration(id, 0x19, &v, 8);
327 			if (ACPI_SUCCESS(rv))
328 				id->Bus = v;
329 		}
330 	}
331 
332 	return id->Bus;
333 }
334 
335 /*
336  * AcpiOsDerivePciId:
337  *
338  * Derive correct PCI bus# by traversing bridges
339  */
340 void
341 AcpiOsDerivePciId(
342     ACPI_HANDLE        rhandle,
343     ACPI_HANDLE        chandle,
344     ACPI_PCI_ID        **PciId)
345 {
346 	(*PciId)->Bus = get_bus_number(rhandle, chandle, PciId);
347 }
348