185556Siwasaki/*-
285556Siwasaki * Copyright (c) 2001 Mitsuru IWASAKI
385556Siwasaki * All rights reserved.
485556Siwasaki *
585556Siwasaki * Redistribution and use in source and binary forms, with or without
685556Siwasaki * modification, are permitted provided that the following conditions
785556Siwasaki * are met:
885556Siwasaki * 1. Redistributions of source code must retain the above copyright
985556Siwasaki *    notice, this list of conditions and the following disclaimer.
1085556Siwasaki * 2. Redistributions in binary form must reproduce the above copyright
1185556Siwasaki *    notice, this list of conditions and the following disclaimer in the
1285556Siwasaki *    documentation and/or other materials provided with the distribution.
1385556Siwasaki *
1485556Siwasaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1585556Siwasaki * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1685556Siwasaki * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1785556Siwasaki * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1885556Siwasaki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1985556Siwasaki * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2085556Siwasaki * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2185556Siwasaki * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2285556Siwasaki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2385556Siwasaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2485556Siwasaki * SUCH DAMAGE.
2585556Siwasaki */
2685556Siwasaki
27118030Sobrien#include <sys/cdefs.h>
28118030Sobrien__FBSDID("$FreeBSD$");
29118030Sobrien
3085556Siwasaki#include <sys/param.h>
3185556Siwasaki#include <sys/bus.h>
32177157Sjhb#include <sys/kernel.h>
33177157Sjhb#include <sys/module.h>
34189903Sjkim#include <sys/sysctl.h>
35197863Sjkim
36197439Sjhb#include <vm/vm.h>
37197439Sjhb#include <vm/pmap.h>
3885556Siwasaki
39193530Sjkim#include <contrib/dev/acpica/include/acpi.h>
40197439Sjhb#include <contrib/dev/acpica/include/accommon.h>
41197439Sjhb#include <contrib/dev/acpica/include/actables.h>
42193530Sjkim
4385556Siwasaki#include <dev/acpica/acpivar.h>
4485556Siwasaki
45177157Sjhb#include <machine/nexusvar.h>
46177157Sjhb
47190341Sjkimint acpi_resume_beep;
48189903SjkimTUNABLE_INT("debug.acpi.resume_beep", &acpi_resume_beep);
49190341SjkimSYSCTL_INT(_debug_acpi, OID_AUTO, resume_beep, CTLFLAG_RW, &acpi_resume_beep,
50189903Sjkim    0, "Beep the PC speaker when resuming");
51190341Sjkim
52190341Sjkimint acpi_reset_video;
53189903SjkimTUNABLE_INT("hw.acpi.reset_video", &acpi_reset_video);
54189903Sjkim
55120347Speterstatic int intr_model = ACPI_INTR_PIC;
56120347Speter
5785556Siwasakiint
5885556Siwasakiacpi_machdep_init(device_t dev)
5985556Siwasaki{
60215072Sjkim	struct acpi_softc *sc;
6185556Siwasaki
62215097Sjkim	sc = device_get_softc(dev);
63189903Sjkim
64215097Sjkim	acpi_apm_init(sc);
6585556Siwasaki
66120347Speter	if (intr_model != ACPI_INTR_PIC)
67120347Speter		acpi_SetIntrModel(intr_model);
68120347Speter
69217326Smdf	SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx,
70189903Sjkim	    SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO,
71189903Sjkim	    "reset_video", CTLFLAG_RW, &acpi_reset_video, 0,
72189903Sjkim	    "Call the VESA reset BIOS vector on the resume path");
73189903Sjkim
7485556Siwasaki	return (0);
7585556Siwasaki}
76120347Speter
77120347Spetervoid
78120347Speteracpi_SetDefaultIntrModel(int model)
79120347Speter{
80120347Speter
81120347Speter	intr_model = model;
82120347Speter}
83131312Snjl
84131312Snjlint
85131312Snjlacpi_machdep_quirks(int *quirks)
86131312Snjl{
87215072Sjkim
88131312Snjl	return (0);
89131312Snjl}
90136366Snjl
91136366Snjlvoid
92136366Snjlacpi_cpu_c1()
93136366Snjl{
94215072Sjkim
95136366Snjl	__asm __volatile("sti; hlt");
96136366Snjl}
97177157Sjhb
98177157Sjhb/*
99197439Sjhb * Support for mapping ACPI tables during early boot.  Currently this
100197439Sjhb * uses the crashdump map to map each table.  However, the crashdump
101197439Sjhb * map is created in pmap_bootstrap() right after the direct map, so
102197439Sjhb * we should be able to just use pmap_mapbios() here instead.
103197439Sjhb *
104197439Sjhb * This makes the following assumptions about how we use this KVA:
105197439Sjhb * pages 0 and 1 are used to map in the header of each table found via
106197439Sjhb * the RSDT or XSDT and pages 2 to n are used to map in the RSDT or
107197439Sjhb * XSDT.  This has to use 2 pages for the table headers in case a
108197439Sjhb * header spans a page boundary.
109197439Sjhb *
110197439Sjhb * XXX: We don't ensure the table fits in the available address space
111197439Sjhb * in the crashdump map.
112197439Sjhb */
113197439Sjhb
114197439Sjhb/*
115197439Sjhb * Map some memory using the crashdump map.  'offset' is an offset in
116197439Sjhb * pages into the crashdump map to use for the start of the mapping.
117197439Sjhb */
118197439Sjhbstatic void *
119197439Sjhbtable_map(vm_paddr_t pa, int offset, vm_offset_t length)
120197439Sjhb{
121197439Sjhb	vm_offset_t va, off;
122197439Sjhb	void *data;
123197439Sjhb
124197439Sjhb	off = pa & PAGE_MASK;
125246855Sjkim	length = round_page(length + off);
126197439Sjhb	pa = pa & PG_FRAME;
127197439Sjhb	va = (vm_offset_t)pmap_kenter_temporary(pa, offset) +
128197439Sjhb	    (offset * PAGE_SIZE);
129197439Sjhb	data = (void *)(va + off);
130197439Sjhb	length -= PAGE_SIZE;
131197439Sjhb	while (length > 0) {
132197439Sjhb		va += PAGE_SIZE;
133197439Sjhb		pa += PAGE_SIZE;
134197439Sjhb		length -= PAGE_SIZE;
135197439Sjhb		pmap_kenter(va, pa);
136197439Sjhb		invlpg(va);
137197439Sjhb	}
138197439Sjhb	return (data);
139197439Sjhb}
140197439Sjhb
141197439Sjhb/* Unmap memory previously mapped with table_map(). */
142197439Sjhbstatic void
143197439Sjhbtable_unmap(void *data, vm_offset_t length)
144197439Sjhb{
145197439Sjhb	vm_offset_t va, off;
146197439Sjhb
147197439Sjhb	va = (vm_offset_t)data;
148197439Sjhb	off = va & PAGE_MASK;
149246855Sjkim	length = round_page(length + off);
150197439Sjhb	va &= ~PAGE_MASK;
151197439Sjhb	while (length > 0) {
152197439Sjhb		pmap_kremove(va);
153197439Sjhb		invlpg(va);
154197439Sjhb		va += PAGE_SIZE;
155197439Sjhb		length -= PAGE_SIZE;
156197439Sjhb	}
157197439Sjhb}
158197439Sjhb
159197439Sjhb/*
160197439Sjhb * Map a table at a given offset into the crashdump map.  It first
161197439Sjhb * maps the header to determine the table length and then maps the
162197439Sjhb * entire table.
163197439Sjhb */
164197439Sjhbstatic void *
165197439Sjhbmap_table(vm_paddr_t pa, int offset, const char *sig)
166197439Sjhb{
167197439Sjhb	ACPI_TABLE_HEADER *header;
168197439Sjhb	vm_offset_t length;
169197439Sjhb	void *table;
170197439Sjhb
171197439Sjhb	header = table_map(pa, offset, sizeof(ACPI_TABLE_HEADER));
172197439Sjhb	if (strncmp(header->Signature, sig, ACPI_NAME_SIZE) != 0) {
173197439Sjhb		table_unmap(header, sizeof(ACPI_TABLE_HEADER));
174197439Sjhb		return (NULL);
175197439Sjhb	}
176197439Sjhb	length = header->Length;
177197439Sjhb	table_unmap(header, sizeof(ACPI_TABLE_HEADER));
178197439Sjhb	table = table_map(pa, offset, length);
179197439Sjhb	if (ACPI_FAILURE(AcpiTbChecksum(table, length))) {
180197439Sjhb		if (bootverbose)
181197439Sjhb			printf("ACPI: Failed checksum for table %s\n", sig);
182205332Sjhb#if (ACPI_CHECKSUM_ABORT)
183197439Sjhb		table_unmap(table, length);
184197439Sjhb		return (NULL);
185205332Sjhb#endif
186197439Sjhb	}
187197439Sjhb	return (table);
188197439Sjhb}
189197439Sjhb
190197439Sjhb/*
191197439Sjhb * See if a given ACPI table is the requested table.  Returns the
192197439Sjhb * length of the able if it matches or zero on failure.
193197439Sjhb */
194197439Sjhbstatic int
195197439Sjhbprobe_table(vm_paddr_t address, const char *sig)
196197439Sjhb{
197197439Sjhb	ACPI_TABLE_HEADER *table;
198197439Sjhb
199197439Sjhb	table = table_map(address, 0, sizeof(ACPI_TABLE_HEADER));
200197439Sjhb	if (table == NULL) {
201197439Sjhb		if (bootverbose)
202197439Sjhb			printf("ACPI: Failed to map table at 0x%jx\n",
203197439Sjhb			    (uintmax_t)address);
204197439Sjhb		return (0);
205197439Sjhb	}
206197439Sjhb	if (bootverbose)
207197439Sjhb		printf("Table '%.4s' at 0x%jx\n", table->Signature,
208197439Sjhb		    (uintmax_t)address);
209197439Sjhb
210197439Sjhb	if (strncmp(table->Signature, sig, ACPI_NAME_SIZE) != 0) {
211197439Sjhb		table_unmap(table, sizeof(ACPI_TABLE_HEADER));
212197439Sjhb		return (0);
213197439Sjhb	}
214197439Sjhb	table_unmap(table, sizeof(ACPI_TABLE_HEADER));
215197439Sjhb	return (1);
216197439Sjhb}
217197439Sjhb
218197439Sjhb/*
219197439Sjhb * Try to map a table at a given physical address previously returned
220197439Sjhb * by acpi_find_table().
221197439Sjhb */
222197439Sjhbvoid *
223197439Sjhbacpi_map_table(vm_paddr_t pa, const char *sig)
224197439Sjhb{
225197439Sjhb
226197439Sjhb	return (map_table(pa, 0, sig));
227197439Sjhb}
228197439Sjhb
229197439Sjhb/* Unmap a table previously mapped via acpi_map_table(). */
230197439Sjhbvoid
231197439Sjhbacpi_unmap_table(void *table)
232197439Sjhb{
233197439Sjhb	ACPI_TABLE_HEADER *header;
234197439Sjhb
235197439Sjhb	header = (ACPI_TABLE_HEADER *)table;
236197439Sjhb	table_unmap(table, header->Length);
237197439Sjhb}
238197439Sjhb
239197439Sjhb/*
240197439Sjhb * Return the physical address of the requested table or zero if one
241197439Sjhb * is not found.
242197439Sjhb */
243197439Sjhbvm_paddr_t
244197439Sjhbacpi_find_table(const char *sig)
245197439Sjhb{
246197439Sjhb	ACPI_PHYSICAL_ADDRESS rsdp_ptr;
247197439Sjhb	ACPI_TABLE_RSDP *rsdp;
248197439Sjhb	ACPI_TABLE_RSDT *rsdt;
249197439Sjhb	ACPI_TABLE_XSDT *xsdt;
250197439Sjhb	ACPI_TABLE_HEADER *table;
251197439Sjhb	vm_paddr_t addr;
252197439Sjhb	int i, count;
253197439Sjhb
254197439Sjhb	if (resource_disabled("acpi", 0))
255197439Sjhb		return (0);
256197439Sjhb
257197439Sjhb	/*
258197439Sjhb	 * Map in the RSDP.  Since ACPI uses AcpiOsMapMemory() which in turn
259197439Sjhb	 * calls pmap_mapbios() to find the RSDP, we assume that we can use
260197439Sjhb	 * pmap_mapbios() to map the RSDP.
261197439Sjhb	 */
262197439Sjhb	if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0)
263197439Sjhb		return (0);
264197439Sjhb	rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP));
265197439Sjhb	if (rsdp == NULL) {
266197439Sjhb		if (bootverbose)
267197439Sjhb			printf("ACPI: Failed to map RSDP\n");
268197439Sjhb		return (0);
269197439Sjhb	}
270197439Sjhb
271197439Sjhb	/*
272197439Sjhb	 * For ACPI >= 2.0, use the XSDT if it is available.
273197439Sjhb	 * Otherwise, use the RSDT.  We map the XSDT or RSDT at page 2
274197439Sjhb	 * in the crashdump area.  Pages 0 and 1 are used to map in the
275197439Sjhb	 * headers of candidate ACPI tables.
276197439Sjhb	 */
277197439Sjhb	addr = 0;
278197439Sjhb	if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) {
279197439Sjhb		/*
280197439Sjhb		 * AcpiOsGetRootPointer only verifies the checksum for
281197439Sjhb		 * the version 1.0 portion of the RSDP.  Version 2.0 has
282197439Sjhb		 * an additional checksum that we verify first.
283197439Sjhb		 */
284197439Sjhb		if (AcpiTbChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) {
285197439Sjhb			if (bootverbose)
286197439Sjhb				printf("ACPI: RSDP failed extended checksum\n");
287197439Sjhb			return (0);
288197439Sjhb		}
289197439Sjhb		xsdt = map_table(rsdp->XsdtPhysicalAddress, 2, ACPI_SIG_XSDT);
290197439Sjhb		if (xsdt == NULL) {
291197439Sjhb			if (bootverbose)
292197439Sjhb				printf("ACPI: Failed to map XSDT\n");
293197439Sjhb			return (0);
294197439Sjhb		}
295197439Sjhb		count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
296197439Sjhb		    sizeof(UINT64);
297197439Sjhb		for (i = 0; i < count; i++)
298197439Sjhb			if (probe_table(xsdt->TableOffsetEntry[i], sig)) {
299197439Sjhb				addr = xsdt->TableOffsetEntry[i];
300197439Sjhb				break;
301197439Sjhb			}
302197439Sjhb		acpi_unmap_table(xsdt);
303197439Sjhb	} else {
304197439Sjhb		rsdt = map_table(rsdp->RsdtPhysicalAddress, 2, ACPI_SIG_RSDT);
305197439Sjhb		if (rsdt == NULL) {
306197439Sjhb			if (bootverbose)
307197439Sjhb				printf("ACPI: Failed to map RSDT\n");
308197439Sjhb			return (0);
309197439Sjhb		}
310197439Sjhb		count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
311197439Sjhb		    sizeof(UINT32);
312197439Sjhb		for (i = 0; i < count; i++)
313197439Sjhb			if (probe_table(rsdt->TableOffsetEntry[i], sig)) {
314197439Sjhb				addr = rsdt->TableOffsetEntry[i];
315197439Sjhb				break;
316197439Sjhb			}
317197439Sjhb		acpi_unmap_table(rsdt);
318197439Sjhb	}
319197439Sjhb	pmap_unmapbios((vm_offset_t)rsdp, sizeof(ACPI_TABLE_RSDP));
320197439Sjhb	if (addr == 0) {
321197439Sjhb		if (bootverbose)
322197439Sjhb			printf("ACPI: No %s table found\n", sig);
323197439Sjhb		return (0);
324197439Sjhb	}
325197439Sjhb	if (bootverbose)
326197439Sjhb		printf("%s: Found table at 0x%jx\n", sig, (uintmax_t)addr);
327197439Sjhb
328197439Sjhb	/*
329197439Sjhb	 * Verify that we can map the full table and that its checksum is
330197439Sjhb	 * correct, etc.
331197439Sjhb	 */
332197439Sjhb	table = map_table(addr, 0, sig);
333197439Sjhb	if (table == NULL)
334197439Sjhb		return (0);
335197439Sjhb	acpi_unmap_table(table);
336197439Sjhb
337197439Sjhb	return (addr);
338197439Sjhb}
339197439Sjhb
340197439Sjhb/*
341177157Sjhb * ACPI nexus(4) driver.
342177157Sjhb */
343177157Sjhbstatic int
344177157Sjhbnexus_acpi_probe(device_t dev)
345177157Sjhb{
346177157Sjhb	int error;
347177157Sjhb
348177157Sjhb	error = acpi_identify();
349177157Sjhb	if (error)
350177157Sjhb		return (error);
351177157Sjhb
352177157Sjhb	return (BUS_PROBE_DEFAULT);
353177157Sjhb}
354177157Sjhb
355177157Sjhbstatic int
356177157Sjhbnexus_acpi_attach(device_t dev)
357177157Sjhb{
358197863Sjkim	device_t acpi_dev;
359197863Sjkim	int error;
360177157Sjhb
361177157Sjhb	nexus_init_resources();
362177157Sjhb	bus_generic_probe(dev);
363197863Sjkim	acpi_dev = BUS_ADD_CHILD(dev, 10, "acpi", 0);
364197863Sjkim	if (acpi_dev == NULL)
365177157Sjhb		panic("failed to add acpi0 device");
366177157Sjhb
367197863Sjkim	error = bus_generic_attach(dev);
368197863Sjkim	if (error == 0)
369197863Sjkim		acpi_install_wakeup_handler(device_get_softc(acpi_dev));
370197863Sjkim
371197863Sjkim	return (error);
372177157Sjhb}
373177157Sjhb
374177157Sjhbstatic device_method_t nexus_acpi_methods[] = {
375177157Sjhb	/* Device interface */
376177157Sjhb	DEVMETHOD(device_probe,		nexus_acpi_probe),
377177157Sjhb	DEVMETHOD(device_attach,	nexus_acpi_attach),
378177157Sjhb
379177157Sjhb	{ 0, 0 }
380177157Sjhb};
381177157Sjhb
382177157SjhbDEFINE_CLASS_1(nexus, nexus_acpi_driver, nexus_acpi_methods, 1, nexus_driver);
383177157Sjhbstatic devclass_t nexus_devclass;
384177157Sjhb
385177157SjhbDRIVER_MODULE(nexus_acpi, root, nexus_acpi_driver, nexus_devclass, 0, 0);
386