xref: /freebsd/sys/dev/acpi_apple/acpi_apple_platform.c (revision 44ceda0a53bfe0c9b343f1e94a4f6ce67f427be6)
1*44ceda0aSAbdelkader Boudih /*
2*44ceda0aSAbdelkader Boudih  * Copyright (c) 2026 Abdelkader Boudih <seuros@FreeBSD.org>
3*44ceda0aSAbdelkader Boudih  *
4*44ceda0aSAbdelkader Boudih  * SPDX-License-Identifier: BSD-2-Clause
5*44ceda0aSAbdelkader Boudih  */
6*44ceda0aSAbdelkader Boudih 
7*44ceda0aSAbdelkader Boudih /*
8*44ceda0aSAbdelkader Boudih  * Apple platform ACPI: Wake-on-LAN and lid state.
9*44ceda0aSAbdelkader Boudih  *
10*44ceda0aSAbdelkader Boudih  * Walks the ACPI namespace on shutdown calling _PSW(1) on any device
11*44ceda0aSAbdelkader Boudih  * with ACPI_FLAG_WAKE_ENABLED set, arming EC.EWOL for wake on magic
12*44ceda0aSAbdelkader Boudih  * packet.  Also follows acpi_lid(4) to blank and restore the panel
13*44ceda0aSAbdelkader Boudih  * backlight.
14*44ceda0aSAbdelkader Boudih  */
15*44ceda0aSAbdelkader Boudih 
16*44ceda0aSAbdelkader Boudih #include <sys/cdefs.h>
17*44ceda0aSAbdelkader Boudih #include "acpi_apple.h"
18*44ceda0aSAbdelkader Boudih 
19*44ceda0aSAbdelkader Boudih /*
20*44ceda0aSAbdelkader Boudih  * APP9876 and APP000B attach concurrently as ACPI_APPLE_PLATFORM on T2
21*44ceda0aSAbdelkader Boudih  * Macs with a discrete GPU.  Refcount the shutdown and lid hooks here so
22*44ceda0aSAbdelkader Boudih  * the second instance's attach/detach doesn't reinstall or rip out the
23*44ceda0aSAbdelkader Boudih  * first instance's hooks.
24*44ceda0aSAbdelkader Boudih  */
25*44ceda0aSAbdelkader Boudih static struct mtx	acpi_apple_platform_mtx;
26*44ceda0aSAbdelkader Boudih MTX_SYSINIT(acpi_apple_platform_mtx_init, &acpi_apple_platform_mtx,
27*44ceda0aSAbdelkader Boudih     "acpi_apple_platform", MTX_DEF);
28*44ceda0aSAbdelkader Boudih static int		acpi_apple_platform_refs;
29*44ceda0aSAbdelkader Boudih static eventhandler_tag	acpi_apple_shutdown_tag;
30*44ceda0aSAbdelkader Boudih static eventhandler_tag	acpi_apple_lid_tag;
31*44ceda0aSAbdelkader Boudih 
32*44ceda0aSAbdelkader Boudih static ACPI_STATUS
acpi_apple_psw_cb(ACPI_HANDLE handle,UINT32 level __unused,void * context,void ** retval __unused)33*44ceda0aSAbdelkader Boudih acpi_apple_psw_cb(ACPI_HANDLE handle, UINT32 level __unused, void *context,
34*44ceda0aSAbdelkader Boudih     void **retval __unused)
35*44ceda0aSAbdelkader Boudih {
36*44ceda0aSAbdelkader Boudih 	ACPI_HANDLE psw_handle;
37*44ceda0aSAbdelkader Boudih 	device_t dev;
38*44ceda0aSAbdelkader Boudih 	int enable;
39*44ceda0aSAbdelkader Boudih 
40*44ceda0aSAbdelkader Boudih 	enable = (int)(uintptr_t)context;
41*44ceda0aSAbdelkader Boudih 
42*44ceda0aSAbdelkader Boudih 	if (ACPI_FAILURE(AcpiGetHandle(handle, "_PSW", &psw_handle)))
43*44ceda0aSAbdelkader Boudih 		return (AE_OK);
44*44ceda0aSAbdelkader Boudih 
45*44ceda0aSAbdelkader Boudih 	dev = acpi_get_device(handle);
46*44ceda0aSAbdelkader Boudih 	if (dev == NULL)
47*44ceda0aSAbdelkader Boudih 		return (AE_OK);
48*44ceda0aSAbdelkader Boudih 
49*44ceda0aSAbdelkader Boudih 	if (enable && (acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) == 0)
50*44ceda0aSAbdelkader Boudih 		return (AE_OK);
51*44ceda0aSAbdelkader Boudih 
52*44ceda0aSAbdelkader Boudih 	(void)acpi_SetInteger(handle, "_PSW", enable);
53*44ceda0aSAbdelkader Boudih 	if (bootverbose)
54*44ceda0aSAbdelkader Boudih 		device_printf(dev, "acpi_apple: _PSW(%d) on %s\n",
55*44ceda0aSAbdelkader Boudih 		    enable, acpi_name(handle));
56*44ceda0aSAbdelkader Boudih 
57*44ceda0aSAbdelkader Boudih 	return (AE_OK);
58*44ceda0aSAbdelkader Boudih }
59*44ceda0aSAbdelkader Boudih 
60*44ceda0aSAbdelkader Boudih static void
acpi_apple_arm_wol(void * arg __unused,int howto __unused)61*44ceda0aSAbdelkader Boudih acpi_apple_arm_wol(void *arg __unused, int howto __unused)
62*44ceda0aSAbdelkader Boudih {
63*44ceda0aSAbdelkader Boudih 	AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
64*44ceda0aSAbdelkader Boudih 	    ACPI_UINT32_MAX, acpi_apple_psw_cb, NULL,
65*44ceda0aSAbdelkader Boudih 	    (void *)(uintptr_t)1, NULL);
66*44ceda0aSAbdelkader Boudih }
67*44ceda0aSAbdelkader Boudih 
68*44ceda0aSAbdelkader Boudih /*
69*44ceda0aSAbdelkader Boudih  * The GMUX handshake polls for milliseconds, so keep it out of the
70*44ceda0aSAbdelkader Boudih  * acpi_lid(4) notify path, which runs with ACPI_SERIAL(lid) held.
71*44ceda0aSAbdelkader Boudih  */
72*44ceda0aSAbdelkader Boudih static void
acpi_apple_backlight_task(void * context)73*44ceda0aSAbdelkader Boudih acpi_apple_backlight_task(void *context)
74*44ceda0aSAbdelkader Boudih {
75*44ceda0aSAbdelkader Boudih 	if (context != NULL)
76*44ceda0aSAbdelkader Boudih 		acpi_apple_backlight_restore();
77*44ceda0aSAbdelkader Boudih 	else
78*44ceda0aSAbdelkader Boudih 		acpi_apple_backlight_off();
79*44ceda0aSAbdelkader Boudih }
80*44ceda0aSAbdelkader Boudih 
81*44ceda0aSAbdelkader Boudih static void
acpi_apple_lid_event(void * arg __unused,int lid_open)82*44ceda0aSAbdelkader Boudih acpi_apple_lid_event(void *arg __unused, int lid_open)
83*44ceda0aSAbdelkader Boudih {
84*44ceda0aSAbdelkader Boudih 	AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_apple_backlight_task,
85*44ceda0aSAbdelkader Boudih 	    (void *)(uintptr_t)lid_open);
86*44ceda0aSAbdelkader Boudih }
87*44ceda0aSAbdelkader Boudih 
88*44ceda0aSAbdelkader Boudih int
acpi_apple_platform_attach(struct acpi_apple_softc * sc __unused)89*44ceda0aSAbdelkader Boudih acpi_apple_platform_attach(struct acpi_apple_softc *sc __unused)
90*44ceda0aSAbdelkader Boudih {
91*44ceda0aSAbdelkader Boudih 	mtx_lock(&acpi_apple_platform_mtx);
92*44ceda0aSAbdelkader Boudih 	if (acpi_apple_platform_refs++ == 0) {
93*44ceda0aSAbdelkader Boudih 		acpi_apple_shutdown_tag = EVENTHANDLER_REGISTER(
94*44ceda0aSAbdelkader Boudih 		    shutdown_final, acpi_apple_arm_wol, NULL,
95*44ceda0aSAbdelkader Boudih 		    SHUTDOWN_PRI_LAST);
96*44ceda0aSAbdelkader Boudih 		acpi_apple_lid_tag = EVENTHANDLER_REGISTER(acpi_lid_event,
97*44ceda0aSAbdelkader Boudih 		    acpi_apple_lid_event, NULL, EVENTHANDLER_PRI_ANY);
98*44ceda0aSAbdelkader Boudih 	}
99*44ceda0aSAbdelkader Boudih 	mtx_unlock(&acpi_apple_platform_mtx);
100*44ceda0aSAbdelkader Boudih 
101*44ceda0aSAbdelkader Boudih 	return (0);
102*44ceda0aSAbdelkader Boudih }
103*44ceda0aSAbdelkader Boudih 
104*44ceda0aSAbdelkader Boudih void
acpi_apple_platform_detach(struct acpi_apple_softc * sc __unused)105*44ceda0aSAbdelkader Boudih acpi_apple_platform_detach(struct acpi_apple_softc *sc __unused)
106*44ceda0aSAbdelkader Boudih {
107*44ceda0aSAbdelkader Boudih 	mtx_lock(&acpi_apple_platform_mtx);
108*44ceda0aSAbdelkader Boudih 	KASSERT(acpi_apple_platform_refs > 0,
109*44ceda0aSAbdelkader Boudih 	    ("acpi_apple: platform refcount underflow"));
110*44ceda0aSAbdelkader Boudih 	if (acpi_apple_platform_refs > 0 && --acpi_apple_platform_refs == 0) {
111*44ceda0aSAbdelkader Boudih 		if (acpi_apple_lid_tag != NULL) {
112*44ceda0aSAbdelkader Boudih 			EVENTHANDLER_DEREGISTER(acpi_lid_event,
113*44ceda0aSAbdelkader Boudih 			    acpi_apple_lid_tag);
114*44ceda0aSAbdelkader Boudih 			acpi_apple_lid_tag = NULL;
115*44ceda0aSAbdelkader Boudih 		}
116*44ceda0aSAbdelkader Boudih 		if (acpi_apple_shutdown_tag != NULL) {
117*44ceda0aSAbdelkader Boudih 			EVENTHANDLER_DEREGISTER(shutdown_final,
118*44ceda0aSAbdelkader Boudih 			    acpi_apple_shutdown_tag);
119*44ceda0aSAbdelkader Boudih 			acpi_apple_shutdown_tag = NULL;
120*44ceda0aSAbdelkader Boudih 		}
121*44ceda0aSAbdelkader Boudih 	}
122*44ceda0aSAbdelkader Boudih 	mtx_unlock(&acpi_apple_platform_mtx);
123*44ceda0aSAbdelkader Boudih }
124