xref: /dflybsd-src/sys/platform/pc64/acpica/acpi_fadt.c (revision fcf6efefc03a35111797b109fa4994034ebe39ba)
15db2f26eSSascha Wildner /*
25db2f26eSSascha Wildner  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
35db2f26eSSascha Wildner  *
45db2f26eSSascha Wildner  * This code is derived from software contributed to The DragonFly Project
55db2f26eSSascha Wildner  * by Sepherosa Ziehau <sepherosa@gmail.com>
65db2f26eSSascha Wildner  *
75db2f26eSSascha Wildner  * Redistribution and use in source and binary forms, with or without
85db2f26eSSascha Wildner  * modification, are permitted provided that the following conditions
95db2f26eSSascha Wildner  * are met:
105db2f26eSSascha Wildner  *
115db2f26eSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
125db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
135db2f26eSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
145db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer in
155db2f26eSSascha Wildner  *    the documentation and/or other materials provided with the
165db2f26eSSascha Wildner  *    distribution.
175db2f26eSSascha Wildner  * 3. Neither the name of The DragonFly Project nor the names of its
185db2f26eSSascha Wildner  *    contributors may be used to endorse or promote products derived
195db2f26eSSascha Wildner  *    from this software without specific, prior written permission.
205db2f26eSSascha Wildner  *
215db2f26eSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
225db2f26eSSascha Wildner  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
235db2f26eSSascha Wildner  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
245db2f26eSSascha Wildner  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
255db2f26eSSascha Wildner  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
265db2f26eSSascha Wildner  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
275db2f26eSSascha Wildner  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
285db2f26eSSascha Wildner  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
295db2f26eSSascha Wildner  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
305db2f26eSSascha Wildner  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
315db2f26eSSascha Wildner  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
325db2f26eSSascha Wildner  * SUCH DAMAGE.
335db2f26eSSascha Wildner  */
345db2f26eSSascha Wildner 
355db2f26eSSascha Wildner #include <sys/param.h>
365db2f26eSSascha Wildner #include <sys/bus.h>
375db2f26eSSascha Wildner #include <sys/interrupt.h>
385db2f26eSSascha Wildner #include <sys/kernel.h>
395db2f26eSSascha Wildner #include <sys/machintr.h>
405db2f26eSSascha Wildner #include <sys/systm.h>
415db2f26eSSascha Wildner 
428d3ef488SSascha Wildner #include <contrib/dev/acpica/source/include/acpi.h>
438d3ef488SSascha Wildner 
445db2f26eSSascha Wildner #include "acpi_sdt_var.h"
455db2f26eSSascha Wildner #include "acpi_sci_var.h"
465db2f26eSSascha Wildner 
475db2f26eSSascha Wildner #define FADT_VPRINTF(fmt, arg...) \
485db2f26eSSascha Wildner do { \
495db2f26eSSascha Wildner 	if (bootverbose) \
505db2f26eSSascha Wildner 		kprintf("ACPI FADT: " fmt , ##arg); \
515db2f26eSSascha Wildner } while (0)
525db2f26eSSascha Wildner 
535db2f26eSSascha Wildner struct acpi_sci_mode {
545db2f26eSSascha Wildner 	enum intr_trigger	sci_trig;
555db2f26eSSascha Wildner 	enum intr_polarity	sci_pola;
565db2f26eSSascha Wildner };
575db2f26eSSascha Wildner 
585db2f26eSSascha Wildner static int			acpi_sci_irq = -1;
595db2f26eSSascha Wildner static enum intr_trigger	acpi_sci_trig = INTR_TRIGGER_CONFORM;
605db2f26eSSascha Wildner static enum intr_polarity	acpi_sci_pola = INTR_POLARITY_CONFORM;
615db2f26eSSascha Wildner static const struct acpi_sci_mode *acpi_sci_mode1 = NULL;
625db2f26eSSascha Wildner 
635db2f26eSSascha Wildner static const struct acpi_sci_mode acpi_sci_modes[] = {
645db2f26eSSascha Wildner 	/*
655db2f26eSSascha Wildner 	 * NOTE: Order is critical
665db2f26eSSascha Wildner 	 */
675db2f26eSSascha Wildner 	{ INTR_TRIGGER_LEVEL,	INTR_POLARITY_LOW },
685db2f26eSSascha Wildner 	{ INTR_TRIGGER_LEVEL,	INTR_POLARITY_HIGH },
695db2f26eSSascha Wildner 	{ INTR_TRIGGER_EDGE,	INTR_POLARITY_HIGH },
705db2f26eSSascha Wildner 	{ INTR_TRIGGER_EDGE,	INTR_POLARITY_LOW },
715db2f26eSSascha Wildner 
725db2f26eSSascha Wildner 	/* Required last entry */
735db2f26eSSascha Wildner 	{ INTR_TRIGGER_CONFORM,	INTR_POLARITY_CONFORM }
745db2f26eSSascha Wildner };
755db2f26eSSascha Wildner 
76*6957c423SMatthew Dillon /*
77*6957c423SMatthew Dillon  * Set to 1 to stop atkbdc from being configured early, via cninit().
78*6957c423SMatthew Dillon  *
79*6957c423SMatthew Dillon  * Currently set to 0 because this is causing problems for several
80*6957c423SMatthew Dillon  * people.  Can be set to 1 with a tunable.
81*6957c423SMatthew Dillon  */
82*6957c423SMatthew Dillon int acpi_fadt_8042_nolegacy = 0;
83*6957c423SMatthew Dillon TUNABLE_INT("hw.acpi.fadt_8042_nolegacy", &acpi_fadt_8042_nolegacy);
84131acb03SImre Vadász 
855db2f26eSSascha Wildner static void
fadt_probe(void)865db2f26eSSascha Wildner fadt_probe(void)
875db2f26eSSascha Wildner {
888d3ef488SSascha Wildner 	ACPI_TABLE_FADT *fadt;
895db2f26eSSascha Wildner 	vm_paddr_t fadt_paddr;
905db2f26eSSascha Wildner 	enum intr_trigger trig;
915db2f26eSSascha Wildner 	enum intr_polarity pola;
925db2f26eSSascha Wildner 	int enabled = 1;
935db2f26eSSascha Wildner 	char *env;
945db2f26eSSascha Wildner 
958d3ef488SSascha Wildner 	fadt_paddr = sdt_search(ACPI_SIG_FADT);
965db2f26eSSascha Wildner 	if (fadt_paddr == 0) {
97131acb03SImre Vadász 		acpi_fadt_8042_nolegacy = 0;
985db2f26eSSascha Wildner 		kprintf("fadt_probe: can't locate FADT\n");
995db2f26eSSascha Wildner 		return;
1005db2f26eSSascha Wildner 	}
1015db2f26eSSascha Wildner 
1025db2f26eSSascha Wildner 	fadt = sdt_sdth_map(fadt_paddr);
1035db2f26eSSascha Wildner 	KKASSERT(fadt != NULL);
1045db2f26eSSascha Wildner 
1055db2f26eSSascha Wildner 	/*
10631fa8539SSascha Wildner 	 * FADT in ACPI specification 1.0 - 6.0
1075db2f26eSSascha Wildner 	 */
10831fa8539SSascha Wildner 	if (fadt->Header.Revision < 1 || fadt->Header.Revision > 6) {
109fa90647aSSepherosa Ziehau 		kprintf("fadt_probe: unknown FADT revision %d\n",
1108d3ef488SSascha Wildner 			fadt->Header.Revision);
1115db2f26eSSascha Wildner 	}
1125db2f26eSSascha Wildner 
11343376c52SSascha Wildner 	if (fadt->Header.Length < ACPI_FADT_V1_SIZE) {
114131acb03SImre Vadász 		acpi_fadt_8042_nolegacy = 0;
11543376c52SSascha Wildner 		kprintf("fadt_probe: invalid FADT length %u (< %u)\n",
11643376c52SSascha Wildner 		    fadt->Header.Length, ACPI_FADT_V1_SIZE);
1175db2f26eSSascha Wildner 		goto back;
1185db2f26eSSascha Wildner 	}
1195db2f26eSSascha Wildner 
120131acb03SImre Vadász 	if (fadt->Header.Length >= ACPI_FADT_V3_SIZE &&
121131acb03SImre Vadász 	    fadt->Header.Revision >= 3) {
122131acb03SImre Vadász 		if ((fadt->BootFlags & ACPI_FADT_8042) != 0)
123131acb03SImre Vadász 			acpi_fadt_8042_nolegacy = 0;
124131acb03SImre Vadász 	} else {
125131acb03SImre Vadász 		acpi_fadt_8042_nolegacy = 0;
126131acb03SImre Vadász 	}
127131acb03SImre Vadász 
1285db2f26eSSascha Wildner 	kgetenv_int("hw.acpi.sci.enabled", &enabled);
1295db2f26eSSascha Wildner 	if (!enabled)
1305db2f26eSSascha Wildner 		goto back;
1315db2f26eSSascha Wildner 
1328d3ef488SSascha Wildner 	acpi_sci_irq = fadt->SciInterrupt;
1335db2f26eSSascha Wildner 
1345db2f26eSSascha Wildner 	env = kgetenv("hw.acpi.sci.trigger");
1355db2f26eSSascha Wildner 	if (env == NULL)
1365db2f26eSSascha Wildner 		goto back;
1375db2f26eSSascha Wildner 
1385db2f26eSSascha Wildner 	trig = INTR_TRIGGER_CONFORM;
1395db2f26eSSascha Wildner 	if (strcmp(env, "edge") == 0)
1405db2f26eSSascha Wildner 		trig = INTR_TRIGGER_EDGE;
1415db2f26eSSascha Wildner 	else if (strcmp(env, "level") == 0)
1425db2f26eSSascha Wildner 		trig = INTR_TRIGGER_LEVEL;
1435db2f26eSSascha Wildner 
1445db2f26eSSascha Wildner 	kfreeenv(env);
1455db2f26eSSascha Wildner 
1465db2f26eSSascha Wildner 	if (trig == INTR_TRIGGER_CONFORM)
1475db2f26eSSascha Wildner 		goto back;
1485db2f26eSSascha Wildner 
1495db2f26eSSascha Wildner 	env = kgetenv("hw.acpi.sci.polarity");
1505db2f26eSSascha Wildner 	if (env == NULL)
1515db2f26eSSascha Wildner 		goto back;
1525db2f26eSSascha Wildner 
1535db2f26eSSascha Wildner 	pola = INTR_POLARITY_CONFORM;
1545db2f26eSSascha Wildner 	if (strcmp(env, "high") == 0)
1555db2f26eSSascha Wildner 		pola = INTR_POLARITY_HIGH;
1565db2f26eSSascha Wildner 	else if (strcmp(env, "low") == 0)
1575db2f26eSSascha Wildner 		pola = INTR_POLARITY_LOW;
1585db2f26eSSascha Wildner 
1595db2f26eSSascha Wildner 	kfreeenv(env);
1605db2f26eSSascha Wildner 
1615db2f26eSSascha Wildner 	if (pola == INTR_POLARITY_CONFORM)
1625db2f26eSSascha Wildner 		goto back;
1635db2f26eSSascha Wildner 
1645db2f26eSSascha Wildner 	acpi_sci_trig = trig;
1655db2f26eSSascha Wildner 	acpi_sci_pola = pola;
1665db2f26eSSascha Wildner back:
1675db2f26eSSascha Wildner 	if (acpi_sci_irq >= 0) {
1685db2f26eSSascha Wildner 		FADT_VPRINTF("SCI irq %d, %s/%s\n", acpi_sci_irq,
1695db2f26eSSascha Wildner 			     intr_str_trigger(acpi_sci_trig),
1705db2f26eSSascha Wildner 			     intr_str_polarity(acpi_sci_pola));
1715db2f26eSSascha Wildner 	} else {
1725db2f26eSSascha Wildner 		FADT_VPRINTF("SCI is disabled\n");
1735db2f26eSSascha Wildner 	}
1748d3ef488SSascha Wildner 	sdt_sdth_unmap(&fadt->Header);
1755db2f26eSSascha Wildner }
1765db2f26eSSascha Wildner SYSINIT(fadt_probe, SI_BOOT2_PRESMP, SI_ORDER_SECOND, fadt_probe, 0);
1775db2f26eSSascha Wildner 
1785db2f26eSSascha Wildner static void
acpi_sci_dummy_intr(void * dummy __unused,void * frame __unused)1795db2f26eSSascha Wildner acpi_sci_dummy_intr(void *dummy __unused, void *frame __unused)
1805db2f26eSSascha Wildner {
1815db2f26eSSascha Wildner }
1825db2f26eSSascha Wildner 
1835db2f26eSSascha Wildner static boolean_t
acpi_sci_test(const struct acpi_sci_mode * mode)1845db2f26eSSascha Wildner acpi_sci_test(const struct acpi_sci_mode *mode)
1855db2f26eSSascha Wildner {
1865db2f26eSSascha Wildner 	void *sci_desc;
1875db2f26eSSascha Wildner 	long last_cnt;
1885db2f26eSSascha Wildner 
1895db2f26eSSascha Wildner 	FADT_VPRINTF("SCI testing %s/%s\n",
1905db2f26eSSascha Wildner 	    intr_str_trigger(mode->sci_trig),
1915db2f26eSSascha Wildner 	    intr_str_polarity(mode->sci_pola));
1925db2f26eSSascha Wildner 
1935db2f26eSSascha Wildner 	last_cnt = get_interrupt_counter(acpi_sci_irq, 0);
1945db2f26eSSascha Wildner 
1955db2f26eSSascha Wildner 	machintr_legacy_intr_config(acpi_sci_irq,
1965db2f26eSSascha Wildner 	    mode->sci_trig, mode->sci_pola);
1975db2f26eSSascha Wildner 
1985db2f26eSSascha Wildner 	sci_desc = register_int(acpi_sci_irq,
1995db2f26eSSascha Wildner 	    acpi_sci_dummy_intr, NULL, "sci", NULL,
2005db2f26eSSascha Wildner 	    INTR_EXCL | INTR_CLOCK |
2015db2f26eSSascha Wildner 	    INTR_NOPOLL | INTR_MPSAFE | INTR_NOENTROPY, 0);
2025db2f26eSSascha Wildner 
2035db2f26eSSascha Wildner 	DELAY(100 * 1000);
2045db2f26eSSascha Wildner 
2055db2f26eSSascha Wildner 	unregister_int(sci_desc, 0);
2065db2f26eSSascha Wildner 
2075db2f26eSSascha Wildner 	if (get_interrupt_counter(acpi_sci_irq, 0) - last_cnt < 20) {
2085db2f26eSSascha Wildner 		acpi_sci_trig = mode->sci_trig;
2095db2f26eSSascha Wildner 		acpi_sci_pola = mode->sci_pola;
2105db2f26eSSascha Wildner 
2115db2f26eSSascha Wildner 		kprintf("ACPI FADT: SCI select %s/%s\n",
2125db2f26eSSascha Wildner 		    intr_str_trigger(acpi_sci_trig),
2135db2f26eSSascha Wildner 		    intr_str_polarity(acpi_sci_pola));
2145db2f26eSSascha Wildner 		return TRUE;
2155db2f26eSSascha Wildner 	}
2165db2f26eSSascha Wildner 	return FALSE;
2175db2f26eSSascha Wildner }
2185db2f26eSSascha Wildner 
2195db2f26eSSascha Wildner void
acpi_sci_config(void)2205db2f26eSSascha Wildner acpi_sci_config(void)
2215db2f26eSSascha Wildner {
2225db2f26eSSascha Wildner 	const struct acpi_sci_mode *mode;
2235db2f26eSSascha Wildner 
2245db2f26eSSascha Wildner 	KKASSERT(mycpuid == 0);
2255db2f26eSSascha Wildner 
2265db2f26eSSascha Wildner 	if (machintr_legacy_intr_find(acpi_sci_irq,
2275db2f26eSSascha Wildner 	    INTR_TRIGGER_CONFORM, INTR_POLARITY_CONFORM) < 0) {
2285db2f26eSSascha Wildner 		kprintf("ACPI FADT: SCI irq %d is invalid, disable\n",
2295db2f26eSSascha Wildner 		    acpi_sci_irq);
2305db2f26eSSascha Wildner 		acpi_sci_irq = -1;
2315db2f26eSSascha Wildner 		return;
2325db2f26eSSascha Wildner 	}
2335db2f26eSSascha Wildner 
2345db2f26eSSascha Wildner 	if (acpi_sci_irq < 0)
2355db2f26eSSascha Wildner 		return;
2365db2f26eSSascha Wildner 
2375db2f26eSSascha Wildner 	if (acpi_sci_trig != INTR_TRIGGER_CONFORM) {
2385db2f26eSSascha Wildner 		KKASSERT(acpi_sci_pola != INTR_POLARITY_CONFORM);
2395db2f26eSSascha Wildner 		machintr_legacy_intr_config(acpi_sci_irq,
2405db2f26eSSascha Wildner 		    acpi_sci_trig, acpi_sci_pola);
2415db2f26eSSascha Wildner 		return;
2425db2f26eSSascha Wildner 	}
2435db2f26eSSascha Wildner 
2445db2f26eSSascha Wildner 	kprintf("ACPI FADT: SCI testing interrupt mode ...\n");
2455db2f26eSSascha Wildner 	if (acpi_sci_mode1 != NULL) {
2465db2f26eSSascha Wildner 		if (acpi_sci_test(acpi_sci_mode1))
2475db2f26eSSascha Wildner 			return;
2485db2f26eSSascha Wildner 	}
2495db2f26eSSascha Wildner 	for (mode = acpi_sci_modes; mode->sci_trig != INTR_TRIGGER_CONFORM;
2505db2f26eSSascha Wildner 	     ++mode) {
2515db2f26eSSascha Wildner 		if (mode == acpi_sci_mode1)
2525db2f26eSSascha Wildner 			continue;
2535db2f26eSSascha Wildner 		if (acpi_sci_test(mode))
2545db2f26eSSascha Wildner 			return;
2555db2f26eSSascha Wildner 	}
2565db2f26eSSascha Wildner 
2575db2f26eSSascha Wildner 	kprintf("ACPI FADT: no suitable interrupt mode for SCI, disable\n");
2585db2f26eSSascha Wildner 	acpi_sci_irq = -1;
2595db2f26eSSascha Wildner }
2605db2f26eSSascha Wildner 
2615db2f26eSSascha Wildner int
acpi_sci_enabled(void)2625db2f26eSSascha Wildner acpi_sci_enabled(void)
2635db2f26eSSascha Wildner {
2645db2f26eSSascha Wildner 	if (acpi_sci_irq >= 0)
2655db2f26eSSascha Wildner 		return 1;
2665db2f26eSSascha Wildner 	else
2675db2f26eSSascha Wildner 		return 0;
2685db2f26eSSascha Wildner }
2695db2f26eSSascha Wildner 
2705db2f26eSSascha Wildner int
acpi_sci_pci_shareable(void)271737d9e74SSascha Wildner acpi_sci_pci_shareable(void)
2725db2f26eSSascha Wildner {
2735db2f26eSSascha Wildner 	if (acpi_sci_irq >= 0 &&
2745db2f26eSSascha Wildner 	    acpi_sci_trig == INTR_TRIGGER_LEVEL &&
2755db2f26eSSascha Wildner 	    acpi_sci_pola == INTR_POLARITY_LOW)
2765db2f26eSSascha Wildner 		return 1;
2775db2f26eSSascha Wildner 	else
2785db2f26eSSascha Wildner 		return 0;
2795db2f26eSSascha Wildner }
2805db2f26eSSascha Wildner 
2815db2f26eSSascha Wildner int
acpi_sci_irqno(void)2825db2f26eSSascha Wildner acpi_sci_irqno(void)
2835db2f26eSSascha Wildner {
2845db2f26eSSascha Wildner 	return acpi_sci_irq;
2855db2f26eSSascha Wildner }
2865db2f26eSSascha Wildner 
2875db2f26eSSascha Wildner void
acpi_sci_setmode1(enum intr_trigger trig,enum intr_polarity pola)2885db2f26eSSascha Wildner acpi_sci_setmode1(enum intr_trigger trig, enum intr_polarity pola)
2895db2f26eSSascha Wildner {
2905db2f26eSSascha Wildner 	const struct acpi_sci_mode *mode;
2915db2f26eSSascha Wildner 
2925db2f26eSSascha Wildner 	for (mode = acpi_sci_modes; mode->sci_trig != INTR_TRIGGER_CONFORM;
2935db2f26eSSascha Wildner 	     ++mode) {
2945db2f26eSSascha Wildner 		if (mode->sci_trig == trig && mode->sci_pola == pola) {
2955db2f26eSSascha Wildner 			acpi_sci_mode1 = mode;
2965db2f26eSSascha Wildner 			return;
2975db2f26eSSascha Wildner 		}
2985db2f26eSSascha Wildner 	}
2995db2f26eSSascha Wildner }
300