xref: /netbsd-src/sys/dev/acpi/acpica/OsdHardware.c (revision fad4c9f71477ae11cea2ee75ec82151ac770a534)
1 /*	$NetBSD: OsdHardware.c,v 1.2 2006/05/14 21:42:26 elad 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.2 2006/05/14 21:42:26 elad 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 	rv = AcpiOsMapMemory(Address, Width / 8, &LogicalAddress);
133 	if (rv != AE_OK)
134 		return rv;
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 	rv = AcpiOsMapMemory(Address, Width / 8, &LogicalAddress);
170 	if (rv != AE_OK)
171 		return rv;
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 	tag = pci_make_tag(acpi_softc->sc_pc, PciId->Bus, PciId->Device,
210 	    PciId->Function);
211 	tmp = pci_conf_read(acpi_softc->sc_pc, tag, Register & ~3);
212 
213 	switch (Width) {
214 	case 8:
215 		*(uint8_t *) Value = (tmp >> ((Register & 3) * 8)) & 0xff;
216 		break;
217 
218 	case 16:
219 		*(uint16_t *) Value = (tmp >> ((Register & 3) * 8)) & 0xffff;
220 		break;
221 
222 	case 32:
223 		*(uint32_t *) Value = tmp;
224 		break;
225 
226 	default:
227 		return AE_BAD_PARAMETER;
228 	}
229 
230 	return AE_OK;
231 }
232 
233 /*
234  * AcpiOsWritePciConfiguration:
235  *
236  *	Write a value to a PCI configuration register.
237  */
238 ACPI_STATUS
239 AcpiOsWritePciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register,
240     ACPI_INTEGER Value, UINT32 Width)
241 {
242 	pcitag_t tag;
243 	pcireg_t tmp;
244 
245 	/* XXX Need to deal with "segment" ("hose" in Alpha terminology). */
246 
247 	tag = pci_make_tag(acpi_softc->sc_pc, PciId->Bus, PciId->Device,
248 	    PciId->Function);
249 
250 	switch (Width) {
251 	case 8:
252 		tmp = pci_conf_read(acpi_softc->sc_pc, tag, Register & ~3);
253 		tmp &= ~(0xff << ((Register & 3) * 8));
254 		tmp |= (Value << ((Register & 3) * 8));
255 		break;
256 
257 	case 16:
258 		tmp = pci_conf_read(acpi_softc->sc_pc, tag, Register & ~3);
259 		tmp &= ~(0xffff << ((Register & 3) * 8));
260 		tmp |= (Value << ((Register & 3) * 8));
261 		break;
262 
263 	case 32:
264 		tmp = Value;
265 		break;
266 
267 	default:
268 		return AE_BAD_PARAMETER;
269 	}
270 
271 	pci_conf_write(acpi_softc->sc_pc, tag, Register & ~3, tmp);
272 
273 	return AE_OK;
274 }
275 
276 /* get PCI bus# from root bridge recursively */
277 static int
278 get_bus_number(
279     ACPI_HANDLE        rhandle,
280     ACPI_HANDLE        chandle,
281     ACPI_PCI_ID        **PciId)
282 {
283 	ACPI_HANDLE handle;
284 	ACPI_STATUS rv;
285 	ACPI_OBJECT_TYPE type;
286 	ACPI_PCI_ID *id;
287 	ACPI_INTEGER v;
288 	int bus;
289 
290 	id = *PciId;
291 
292 	rv = AcpiGetParent(chandle, &handle);
293 	if (ACPI_FAILURE(rv))
294 		return 0;
295 
296 	/*
297 	 * When handle == rhandle, we have valid PciId->Bus
298 	 * which was obtained from _BBN in evrgnini.c
299 	 * so we don't have to reevaluate _BBN.
300 	 */
301 	if (handle != rhandle) {
302 		bus = get_bus_number(rhandle, handle, PciId);
303 
304 		rv = AcpiGetType(handle, &type);
305 		if (ACPI_FAILURE(rv) || type != ACPI_TYPE_DEVICE)
306 			return bus;
307 
308 		rv = acpi_eval_integer(handle, METHOD_NAME__ADR, &v);
309 
310 		if (ACPI_FAILURE(rv))
311 			return bus;
312 
313 		id->Bus = bus;
314 		id->Device = ACPI_HIWORD((ACPI_INTEGER)v);
315 		id->Function = ACPI_LOWORD((ACPI_INTEGER)v);
316 
317 		/* read HDR_TYPE register */
318 		rv = AcpiOsReadPciConfiguration(id, 0x0e, &v, 8);
319 		if (ACPI_SUCCESS(rv) &&
320 			/* mask multifunction bit & check bridge type */
321 			((v & 0x7f) == 1 || (v & 0x7f) == 2)) {
322 			/* read SECONDARY_BUS register */
323 			rv = AcpiOsReadPciConfiguration(id, 0x19, &v, 8);
324 			if (ACPI_SUCCESS(rv))
325 				id->Bus = v;
326 		}
327 	}
328 
329 	return id->Bus;
330 }
331 
332 /*
333  * AcpiOsDerivePciId:
334  *
335  * Derive correct PCI bus# by traversing bridges
336  */
337 void
338 AcpiOsDerivePciId(
339     ACPI_HANDLE        rhandle,
340     ACPI_HANDLE        chandle,
341     ACPI_PCI_ID        **PciId)
342 {
343 	(*PciId)->Bus = get_bus_number(rhandle, chandle, PciId);
344 }
345