1f86214b6SMitsuru IWASAKI /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3c49761ddSPedro F. Giffuni *
4f86214b6SMitsuru IWASAKI * Copyright (c) 2001 Mitsuru IWASAKI
5f86214b6SMitsuru IWASAKI * All rights reserved.
6f86214b6SMitsuru IWASAKI *
7f86214b6SMitsuru IWASAKI * Redistribution and use in source and binary forms, with or without
8f86214b6SMitsuru IWASAKI * modification, are permitted provided that the following conditions
9f86214b6SMitsuru IWASAKI * are met:
10f86214b6SMitsuru IWASAKI * 1. Redistributions of source code must retain the above copyright
11f86214b6SMitsuru IWASAKI * notice, this list of conditions and the following disclaimer.
12f86214b6SMitsuru IWASAKI * 2. Redistributions in binary form must reproduce the above copyright
13f86214b6SMitsuru IWASAKI * notice, this list of conditions and the following disclaimer in the
14f86214b6SMitsuru IWASAKI * documentation and/or other materials provided with the distribution.
15f86214b6SMitsuru IWASAKI *
16f86214b6SMitsuru IWASAKI * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17f86214b6SMitsuru IWASAKI * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18f86214b6SMitsuru IWASAKI * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f86214b6SMitsuru IWASAKI * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20f86214b6SMitsuru IWASAKI * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f86214b6SMitsuru IWASAKI * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22f86214b6SMitsuru IWASAKI * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f86214b6SMitsuru IWASAKI * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24f86214b6SMitsuru IWASAKI * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f86214b6SMitsuru IWASAKI * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f86214b6SMitsuru IWASAKI * SUCH DAMAGE.
27f86214b6SMitsuru IWASAKI */
28f86214b6SMitsuru IWASAKI
29f86214b6SMitsuru IWASAKI #include <sys/param.h>
30f86214b6SMitsuru IWASAKI #include <sys/bus.h>
315217af30SJohn Baldwin #include <sys/kernel.h>
325217af30SJohn Baldwin #include <sys/module.h>
33c66d2b38SJung-uk Kim #include <sys/sysctl.h>
34a7e2341eSJung-uk Kim
35d95e7f5aSJohn Baldwin #include <vm/vm.h>
36d95e7f5aSJohn Baldwin #include <vm/pmap.h>
37f86214b6SMitsuru IWASAKI
38129d3046SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h>
39d95e7f5aSJohn Baldwin #include <contrib/dev/acpica/include/accommon.h>
40d95e7f5aSJohn Baldwin #include <contrib/dev/acpica/include/actables.h>
41129d3046SJung-uk Kim
42f86214b6SMitsuru IWASAKI #include <dev/acpica/acpivar.h>
43f86214b6SMitsuru IWASAKI
445217af30SJohn Baldwin #include <machine/nexusvar.h>
455217af30SJohn Baldwin
46d2b227cdSJung-uk Kim int acpi_resume_beep;
47af3b2549SHans Petter Selasky SYSCTL_INT(_debug_acpi, OID_AUTO, resume_beep, CTLFLAG_RWTUN,
48af3b2549SHans Petter Selasky &acpi_resume_beep, 0, "Beep the PC speaker when resuming");
49d2b227cdSJung-uk Kim
50d2b227cdSJung-uk Kim int acpi_reset_video;
51c66d2b38SJung-uk Kim TUNABLE_INT("hw.acpi.reset_video", &acpi_reset_video);
52c66d2b38SJung-uk Kim
538848ad86SPeter Wemm static int intr_model = ACPI_INTR_PIC;
548848ad86SPeter Wemm
55f86214b6SMitsuru IWASAKI int
acpi_machdep_init(device_t dev)56f86214b6SMitsuru IWASAKI acpi_machdep_init(device_t dev)
57f86214b6SMitsuru IWASAKI {
58f86214b6SMitsuru IWASAKI struct acpi_softc *sc;
59f86214b6SMitsuru IWASAKI
6093a88474SJung-uk Kim sc = device_get_softc(dev);
61c66d2b38SJung-uk Kim
6293a88474SJung-uk Kim acpi_apm_init(sc);
630ef8c0cbSJung-uk Kim acpi_install_wakeup_handler(sc);
64f86214b6SMitsuru IWASAKI
658848ad86SPeter Wemm if (intr_model != ACPI_INTR_PIC)
668848ad86SPeter Wemm acpi_SetIntrModel(intr_model);
678848ad86SPeter Wemm
68fbbb13f9SMatthew D Fleming SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx,
69c66d2b38SJung-uk Kim SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO,
70c66d2b38SJung-uk Kim "reset_video", CTLFLAG_RW, &acpi_reset_video, 0,
71c66d2b38SJung-uk Kim "Call the VESA reset BIOS vector on the resume path");
72c66d2b38SJung-uk Kim
73f86214b6SMitsuru IWASAKI return (0);
74f86214b6SMitsuru IWASAKI }
758848ad86SPeter Wemm
768848ad86SPeter Wemm void
acpi_SetDefaultIntrModel(int model)778848ad86SPeter Wemm acpi_SetDefaultIntrModel(int model)
788848ad86SPeter Wemm {
798848ad86SPeter Wemm
808848ad86SPeter Wemm intr_model = model;
818848ad86SPeter Wemm }
821a26ea7fSNate Lawson
831a26ea7fSNate Lawson int
acpi_machdep_quirks(int * quirks)841a26ea7fSNate Lawson acpi_machdep_quirks(int *quirks)
851a26ea7fSNate Lawson {
867c2bf852SJung-uk Kim
871a26ea7fSNate Lawson return (0);
881a26ea7fSNate Lawson }
8931ad3b88SNate Lawson
905217af30SJohn Baldwin /*
9172c7f24cSMark Johnston * Map a table. First map the header to determine the table length and then map
9272c7f24cSMark Johnston * the entire table.
93d95e7f5aSJohn Baldwin */
94d95e7f5aSJohn Baldwin static void *
map_table(vm_paddr_t pa,const char * sig)9572c7f24cSMark Johnston map_table(vm_paddr_t pa, const char *sig)
96d95e7f5aSJohn Baldwin {
97d95e7f5aSJohn Baldwin ACPI_TABLE_HEADER *header;
9852fba9a9SJessica Clarke vm_size_t length;
99d95e7f5aSJohn Baldwin void *table;
100d95e7f5aSJohn Baldwin
10172c7f24cSMark Johnston header = pmap_mapbios(pa, sizeof(ACPI_TABLE_HEADER));
102278f0de6SJung-uk Kim if (strncmp(header->Signature, sig, ACPI_NAMESEG_SIZE) != 0) {
1037ae99f80SJohn Baldwin pmap_unmapbios(header, sizeof(ACPI_TABLE_HEADER));
104d95e7f5aSJohn Baldwin return (NULL);
105d95e7f5aSJohn Baldwin }
106d95e7f5aSJohn Baldwin length = header->Length;
1077ae99f80SJohn Baldwin pmap_unmapbios(header, sizeof(ACPI_TABLE_HEADER));
10872c7f24cSMark Johnston table = pmap_mapbios(pa, length);
10919ee8335SJung-uk Kim if (ACPI_FAILURE(AcpiUtChecksum(table, length))) {
110d95e7f5aSJohn Baldwin if (bootverbose)
111d95e7f5aSJohn Baldwin printf("ACPI: Failed checksum for table %s\n", sig);
11242c93b8dSJohn Baldwin #if (ACPI_CHECKSUM_ABORT)
1137ae99f80SJohn Baldwin pmap_unmapbios(table, length);
114d95e7f5aSJohn Baldwin return (NULL);
11542c93b8dSJohn Baldwin #endif
116d95e7f5aSJohn Baldwin }
117d95e7f5aSJohn Baldwin return (table);
118d95e7f5aSJohn Baldwin }
119d95e7f5aSJohn Baldwin
120d95e7f5aSJohn Baldwin /*
121d95e7f5aSJohn Baldwin * See if a given ACPI table is the requested table. Returns the
12243909748SJessica Clarke * length of the table if it matches or zero on failure.
123d95e7f5aSJohn Baldwin */
124d95e7f5aSJohn Baldwin static int
probe_table(vm_paddr_t address,const char * sig)125d95e7f5aSJohn Baldwin probe_table(vm_paddr_t address, const char *sig)
126d95e7f5aSJohn Baldwin {
127d95e7f5aSJohn Baldwin ACPI_TABLE_HEADER *table;
12872c7f24cSMark Johnston int ret;
129d95e7f5aSJohn Baldwin
13072c7f24cSMark Johnston table = pmap_mapbios(address, sizeof(ACPI_TABLE_HEADER));
13172c7f24cSMark Johnston ret = strncmp(table->Signature, sig, ACPI_NAMESEG_SIZE) == 0;
1327ae99f80SJohn Baldwin pmap_unmapbios(table, sizeof(ACPI_TABLE_HEADER));
13372c7f24cSMark Johnston return (ret);
134d95e7f5aSJohn Baldwin }
135d95e7f5aSJohn Baldwin
136d95e7f5aSJohn Baldwin /*
137d95e7f5aSJohn Baldwin * Try to map a table at a given physical address previously returned
138d95e7f5aSJohn Baldwin * by acpi_find_table().
139d95e7f5aSJohn Baldwin */
140d95e7f5aSJohn Baldwin void *
acpi_map_table(vm_paddr_t pa,const char * sig)141d95e7f5aSJohn Baldwin acpi_map_table(vm_paddr_t pa, const char *sig)
142d95e7f5aSJohn Baldwin {
143d95e7f5aSJohn Baldwin
14472c7f24cSMark Johnston return (map_table(pa, sig));
145d95e7f5aSJohn Baldwin }
146d95e7f5aSJohn Baldwin
147d95e7f5aSJohn Baldwin /* Unmap a table previously mapped via acpi_map_table(). */
148d95e7f5aSJohn Baldwin void
acpi_unmap_table(void * table)149d95e7f5aSJohn Baldwin acpi_unmap_table(void *table)
150d95e7f5aSJohn Baldwin {
151d95e7f5aSJohn Baldwin ACPI_TABLE_HEADER *header;
152d95e7f5aSJohn Baldwin
153d95e7f5aSJohn Baldwin header = (ACPI_TABLE_HEADER *)table;
1547ae99f80SJohn Baldwin pmap_unmapbios(table, header->Length);
155d95e7f5aSJohn Baldwin }
156d95e7f5aSJohn Baldwin
157d95e7f5aSJohn Baldwin /*
158d95e7f5aSJohn Baldwin * Return the physical address of the requested table or zero if one
159d95e7f5aSJohn Baldwin * is not found.
160d95e7f5aSJohn Baldwin */
161d95e7f5aSJohn Baldwin vm_paddr_t
acpi_find_table(const char * sig)162d95e7f5aSJohn Baldwin acpi_find_table(const char *sig)
163d95e7f5aSJohn Baldwin {
164d95e7f5aSJohn Baldwin ACPI_PHYSICAL_ADDRESS rsdp_ptr;
165d95e7f5aSJohn Baldwin ACPI_TABLE_RSDP *rsdp;
166d95e7f5aSJohn Baldwin ACPI_TABLE_RSDT *rsdt;
167d95e7f5aSJohn Baldwin ACPI_TABLE_XSDT *xsdt;
168d95e7f5aSJohn Baldwin ACPI_TABLE_HEADER *table;
169d95e7f5aSJohn Baldwin vm_paddr_t addr;
170d95e7f5aSJohn Baldwin int i, count;
171d95e7f5aSJohn Baldwin
172d95e7f5aSJohn Baldwin if (resource_disabled("acpi", 0))
173d95e7f5aSJohn Baldwin return (0);
174d95e7f5aSJohn Baldwin
175d95e7f5aSJohn Baldwin /*
176d95e7f5aSJohn Baldwin * Map in the RSDP. Since ACPI uses AcpiOsMapMemory() which in turn
177d95e7f5aSJohn Baldwin * calls pmap_mapbios() to find the RSDP, we assume that we can use
178d95e7f5aSJohn Baldwin * pmap_mapbios() to map the RSDP.
179d95e7f5aSJohn Baldwin */
180d95e7f5aSJohn Baldwin if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0)
181d95e7f5aSJohn Baldwin return (0);
182d95e7f5aSJohn Baldwin rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP));
183d95e7f5aSJohn Baldwin if (rsdp == NULL) {
184d95e7f5aSJohn Baldwin printf("ACPI: Failed to map RSDP\n");
185d95e7f5aSJohn Baldwin return (0);
186d95e7f5aSJohn Baldwin }
187d95e7f5aSJohn Baldwin
188d95e7f5aSJohn Baldwin /*
189d95e7f5aSJohn Baldwin * For ACPI >= 2.0, use the XSDT if it is available.
19072c7f24cSMark Johnston * Otherwise, use the RSDT.
191d95e7f5aSJohn Baldwin */
192d95e7f5aSJohn Baldwin addr = 0;
193d95e7f5aSJohn Baldwin if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) {
194d95e7f5aSJohn Baldwin /*
195d95e7f5aSJohn Baldwin * AcpiOsGetRootPointer only verifies the checksum for
196d95e7f5aSJohn Baldwin * the version 1.0 portion of the RSDP. Version 2.0 has
197d95e7f5aSJohn Baldwin * an additional checksum that we verify first.
198d95e7f5aSJohn Baldwin */
19919ee8335SJung-uk Kim if (AcpiUtChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) {
200d95e7f5aSJohn Baldwin printf("ACPI: RSDP failed extended checksum\n");
2017ae99f80SJohn Baldwin pmap_unmapbios(rsdp, sizeof(ACPI_TABLE_RSDP));
202d95e7f5aSJohn Baldwin return (0);
203d95e7f5aSJohn Baldwin }
20472c7f24cSMark Johnston xsdt = map_table(rsdp->XsdtPhysicalAddress, ACPI_SIG_XSDT);
205d95e7f5aSJohn Baldwin if (xsdt == NULL) {
206d95e7f5aSJohn Baldwin printf("ACPI: Failed to map XSDT\n");
2077ae99f80SJohn Baldwin pmap_unmapbios(rsdp, sizeof(ACPI_TABLE_RSDP));
208d95e7f5aSJohn Baldwin return (0);
209d95e7f5aSJohn Baldwin }
210d95e7f5aSJohn Baldwin count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
211d95e7f5aSJohn Baldwin sizeof(UINT64);
212d95e7f5aSJohn Baldwin for (i = 0; i < count; i++)
213d95e7f5aSJohn Baldwin if (probe_table(xsdt->TableOffsetEntry[i], sig)) {
214d95e7f5aSJohn Baldwin addr = xsdt->TableOffsetEntry[i];
215d95e7f5aSJohn Baldwin break;
216d95e7f5aSJohn Baldwin }
217d95e7f5aSJohn Baldwin acpi_unmap_table(xsdt);
218d95e7f5aSJohn Baldwin } else {
21972c7f24cSMark Johnston rsdt = map_table(rsdp->RsdtPhysicalAddress, ACPI_SIG_RSDT);
220d95e7f5aSJohn Baldwin if (rsdt == NULL) {
221d95e7f5aSJohn Baldwin printf("ACPI: Failed to map RSDT\n");
2227ae99f80SJohn Baldwin pmap_unmapbios(rsdp, sizeof(ACPI_TABLE_RSDP));
223d95e7f5aSJohn Baldwin return (0);
224d95e7f5aSJohn Baldwin }
225d95e7f5aSJohn Baldwin count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
226d95e7f5aSJohn Baldwin sizeof(UINT32);
227d95e7f5aSJohn Baldwin for (i = 0; i < count; i++)
228d95e7f5aSJohn Baldwin if (probe_table(rsdt->TableOffsetEntry[i], sig)) {
229d95e7f5aSJohn Baldwin addr = rsdt->TableOffsetEntry[i];
230d95e7f5aSJohn Baldwin break;
231d95e7f5aSJohn Baldwin }
232d95e7f5aSJohn Baldwin acpi_unmap_table(rsdt);
233d95e7f5aSJohn Baldwin }
2347ae99f80SJohn Baldwin pmap_unmapbios(rsdp, sizeof(ACPI_TABLE_RSDP));
2358f6355b5SAlexander Motin if (addr == 0)
236d95e7f5aSJohn Baldwin return (0);
237d95e7f5aSJohn Baldwin
238d95e7f5aSJohn Baldwin /*
239d95e7f5aSJohn Baldwin * Verify that we can map the full table and that its checksum is
240d95e7f5aSJohn Baldwin * correct, etc.
241d95e7f5aSJohn Baldwin */
24272c7f24cSMark Johnston table = map_table(addr, sig);
243d95e7f5aSJohn Baldwin if (table == NULL)
244d95e7f5aSJohn Baldwin return (0);
245d95e7f5aSJohn Baldwin acpi_unmap_table(table);
246d95e7f5aSJohn Baldwin
247d95e7f5aSJohn Baldwin return (addr);
248d95e7f5aSJohn Baldwin }
249d95e7f5aSJohn Baldwin
250d95e7f5aSJohn Baldwin /*
2515217af30SJohn Baldwin * ACPI nexus(4) driver.
2525217af30SJohn Baldwin */
2535217af30SJohn Baldwin static int
nexus_acpi_probe(device_t dev)2545217af30SJohn Baldwin nexus_acpi_probe(device_t dev)
2555217af30SJohn Baldwin {
2565217af30SJohn Baldwin int error;
2575217af30SJohn Baldwin
2585217af30SJohn Baldwin error = acpi_identify();
2595217af30SJohn Baldwin if (error)
2605217af30SJohn Baldwin return (error);
261732b69c9SMark Johnston device_quiet(dev);
2625217af30SJohn Baldwin return (BUS_PROBE_DEFAULT);
2635217af30SJohn Baldwin }
2645217af30SJohn Baldwin
2655217af30SJohn Baldwin static int
nexus_acpi_attach(device_t dev)2665217af30SJohn Baldwin nexus_acpi_attach(device_t dev)
2675217af30SJohn Baldwin {
2685217af30SJohn Baldwin
2695217af30SJohn Baldwin nexus_init_resources();
2705217af30SJohn Baldwin bus_generic_probe(dev);
2710ef8c0cbSJung-uk Kim if (BUS_ADD_CHILD(dev, 10, "acpi", 0) == NULL)
2725217af30SJohn Baldwin panic("failed to add acpi0 device");
2735217af30SJohn Baldwin
2740ef8c0cbSJung-uk Kim return (bus_generic_attach(dev));
2755217af30SJohn Baldwin }
2765217af30SJohn Baldwin
2775217af30SJohn Baldwin static device_method_t nexus_acpi_methods[] = {
2785217af30SJohn Baldwin /* Device interface */
2795217af30SJohn Baldwin DEVMETHOD(device_probe, nexus_acpi_probe),
2805217af30SJohn Baldwin DEVMETHOD(device_attach, nexus_acpi_attach),
2815217af30SJohn Baldwin { 0, 0 }
2825217af30SJohn Baldwin };
2835217af30SJohn Baldwin
2845217af30SJohn Baldwin DEFINE_CLASS_1(nexus, nexus_acpi_driver, nexus_acpi_methods, 1, nexus_driver);
2855217af30SJohn Baldwin
286badcc74fSJohn Baldwin DRIVER_MODULE(nexus_acpi, root, nexus_acpi_driver, 0, 0);
287