1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <console/console.h>
5 #include <cpu/x86/msr.h>
6 #include <cpu/x86/smm.h>
7 #include <ec/acpi/ec.h>
11 * TODO: Perform RE of protocols in vendor firmware:
12 * - gEfiSmmSxDispatch2ProtocolGuid
13 * - gEfiSmmPowerButtonDispatch2ProtocolGuid
15 * However, note that first glance suggests that no handlers
16 * will be very interesting and that gEfiSmmGpiDispatch2ProtocolGuid
17 * was unused (as I recall).
19 * Also, consider gEfiSmmIoTrapDispatch2ProtocolGuid, but
20 * this is less likely.
23 /* Keep in sync with dsdt.asl; could insert into SSDT at runtime */
24 #define APM_CNT_BOARD_SMI 0xDD
26 /* Toggle TURBO_MODE_DISABLE bit in IA32_MISC_ENABLE MSR
27 when requested by EC. */
28 static void toggle_turbo_disable(uint8_t function_parameter_0
)
30 if (function_parameter_0
== 1) {
31 printk(BIOS_DEBUG
, "EC: Enabling Intel Turbo Mode\n");
32 msr_unset(IA32_MISC_ENABLE
, 0x4000000000);
33 } else if (function_parameter_0
== 0) {
34 printk(BIOS_DEBUG
, "EC: Disabling Intel Turbo Mode\n");
35 msr_set(IA32_MISC_ENABLE
, 0x4000000000);
39 /* Set WiFi and BT enable bits in EC RAM. */
40 static void enable_rf_by_capability(void)
42 /* FIXME: We're not tracking (driver) 'capabilities' at the moment (must we?),
43 so we just enable WiFi and BT here. If this was tracked, then
44 bits may be cleared here */
45 uint8_t rf_register
= ec_read(0x71);
46 ec_write(0x71, rf_register
| 0x03);
49 /* Set OS capability bits in EC RAM. */
50 static void handle_acpi_osys(void)
54 /* TODO: Add _OSI method support to coreboot and make this work */
55 printk(BIOS_DEBUG
, "GNVS.OSYS = %d\n", gnvs
->unused_was_osys
);
56 switch (gnvs
->unused_was_osys
) {
61 /* Windows versions by year */
74 /* Operating system unknown */
76 printk(BIOS_DEBUG
, "GNVS.OSYS not supported!\n");
77 printk(BIOS_DEBUG
, "No capabilities!\n");
82 ec_write(0x5C, os_support
);
85 /* Handles EC's _REG, _PTS and _WAK methods.
86 Partially involves setting EC RAM offsets based on GNVS.OSYS - OS capabilities? */
87 static void handle_acpi_wake_event(
88 uint8_t function_parameter_0
, uint8_t function_parameter_1
)
90 switch (function_parameter_0
) {
92 printk(BIOS_DEBUG
, "EC: Called for _REG method - OS initialise\n");
93 enable_rf_by_capability();
95 // NOTE: Not handling (driver) 'capabilities'
98 printk(BIOS_DEBUG
, "EC: Called for _PTS method - Entering sleep\n");
99 // NOTE: Not saving (driver) 'capabilities'
100 // NOTE: Not saving and restoring EC RAM offset 0x4F
103 printk(BIOS_DEBUG
, "EC: Called for _WAK method - Sleep resume\n");
104 enable_rf_by_capability();
106 // NOTE: Not saving and restoring EC RAM offset 0x4F
109 printk(BIOS_DEBUG
, "function_parameter_0 is invalid!\n");
114 /* TODO: Reverse engineer 0x80 function and implement if necessary */
115 static void ec_smi_handler(uint8_t smif
)
117 uint8_t smm_data_port
;
118 uint8_t function_parameter_0
;
119 uint8_t function_parameter_1
;
121 /* Parameters encoded onto SMI data port because PRMx NVS are not present
122 - Callers must only use 4 bits per argument
123 - _PTS and _WAK are required to call in spec-compliant way */
124 smm_data_port
= inb(APM_STS
);
125 function_parameter_0
= smm_data_port
& ~0xF0;
126 function_parameter_1
= smm_data_port
>> 4;
128 printk(BIOS_DEBUG
, "Function 0x%x(0x%x, 0x%x) called\n",
129 smif
, function_parameter_0
, function_parameter_1
);
132 printk(BIOS_WARNING
, "Function 0x80 is unimplemented!\n");
133 printk(BIOS_DEBUG
, "Function calls offset 0 in ACER_BOOT_DEVICE_SERVICE_PROTOCOL_GUID\n");
136 toggle_turbo_disable(function_parameter_0
);
139 handle_acpi_wake_event(function_parameter_0
, function_parameter_1
);
143 printk(BIOS_DEBUG
, "Requested function is unknown!\n");
149 * - On success, the handler returns 0
150 * - On failure, the handler returns a value != 0
155 int mainboard_smi_apmc(u8 data
)
157 /* TODO: Continue SmmKbcDriver RE of common service registration and confirm */
159 case APM_CNT_BOARD_SMI
:
161 ec_smi_handler(gnvs
->smif
);
164 case APM_CNT_ACPI_ENABLE
: /* Events generate SCIs for OS */
165 /* use 0x68/0x6C to prevent races with userspace */
166 ec_set_ports(0x6C, 0x68);
167 /* discard all events */
168 ec_clear_out_queue();
169 /* Tests at runtime show this re-enables charging and battery reporting */
170 send_ec_command(0xE9); /* Vendor implements using ACPI "CMDB" register" */
172 /* TODO: Set touchpad GPP owner to ACPI? */
174 case APM_CNT_ACPI_DISABLE
: /* Events generate SMIs for SMM */
175 /* use 0x68/0x6C to prevent races with userspace */
176 ec_set_ports(0x6C, 0x68);
177 /* discard all events */
178 ec_clear_out_queue();
179 /* Tests at runtime show this disables charging and battery reporting */
180 send_ec_command(0xE9); /* Vendor implements using ACPI "CMDB" register" */
182 /* TODO: Set touchpad GPP owner to GPIO? */