Documentation: Add wake source info to device tree documentation

The device tree documentation was promoting using a GPIO wake event and
a GPE wake event. We should only ever have one. This wasn't actually
causing a problem because the wake bit was set on the `irq` property,
but the IO-APIC can't actually wake the system, so it was a no-op.

This change fixes up the markdown so it's formatted correctly, and also
adds a section explaining what the different wake configurations are.

BUG=b:243700486
TEST=mdformat

Signed-off-by: Raul E Rangel <rrangel@chromium.org>
Change-Id: Ifcdbd5371408784bf9b81c1ade90263de8c60e0f
Reviewed-on: https://review.coreboot.org/c/coreboot/+/67385
Reviewed-by: Karthik Ramasubramanian <kramasub@google.com>
Reviewed-by: Tim Van Patten <timvp@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Raul E Rangel 2022-09-06 14:32:59 -06:00 committed by Martin Roth
parent ae7d8379a5
commit 0e9cc44d1b
1 changed files with 92 additions and 22 deletions

View File

@ -8,7 +8,7 @@ device pci 15.0 on
chip drivers/i2c/generic chip drivers/i2c/generic
register "hid" = ""ELAN0000"" register "hid" = ""ELAN0000""
register "desc" = ""ELAN Touchpad"" register "desc" = ""ELAN Touchpad""
register "irq" = "ACPI_IRQ_WAKE_LEVEL_LOW(GPP_A21_IRQ)" register "irq" = "ACPI_IRQ_LEVEL_LOW(GPP_A21_IRQ)"
register "detect" = "1" register "detect" = "1"
register "wake" = "GPE0_DW0_21" register "wake" = "GPE0_DW0_21"
device i2c 15 on end device i2c 15 on end
@ -39,7 +39,7 @@ Scope (\_SB.PCI0.I2C0)
I2cSerialBusV2 (0x0015, ControllerInitiated, 400000, I2cSerialBusV2 (0x0015, ControllerInitiated, 400000,
AddressingMode7Bit, "\\_SB.PCI0.I2C0", AddressingMode7Bit, "\\_SB.PCI0.I2C0",
0x00, ResourceConsumer, , Exclusive, ) 0x00, ResourceConsumer, , Exclusive, )
Interrupt (ResourceConsumer, Level, ActiveLow, ExclusiveAndWake, ,, ) Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive, ,, )
{ {
0x0000002D, 0x0000002D,
} }
@ -54,7 +54,7 @@ Scope (\_SB.PCI0.I2C0)
} }
``` ```
You can see it generates _HID, _UID, _DDN, _STA, _CRS, _S0W, and _PRW You can see it generates \_HID, \_UID, \_DDN, \_STA, \_CRS, \_S0W, and \_PRW
names/methods in the Device's scope. names/methods in the Device's scope.
## Utilizing a device driver ## Utilizing a device driver
@ -88,7 +88,7 @@ be included in the ACPI table.
register "hid" = ""ELAN0000"" register "hid" = ""ELAN0000""
``` ```
This corresponds to **const char *hid** in the struct. In the ACPI ASL, it This corresponds to **const char \*hid** in the struct. In the ACPI ASL, it
translates to: translates to:
``` ```
@ -104,7 +104,7 @@ during enumeration in the OS.**
register "desc" = ""ELAN Touchpad"" register "desc" = ""ELAN Touchpad""
``` ```
corresponds to **const char *desc** and in ASL: corresponds to **const char \*desc** and in ASL:
``` ```
Name (_DDN, "ELAN Touchpad") // _DDN: DOS Device Name Name (_DDN, "ELAN Touchpad") // _DDN: DOS Device Name
@ -115,7 +115,7 @@ corresponds to **const char *desc** and in ASL:
It also adds the interrupt, It also adds the interrupt,
``` ```
Interrupt (ResourceConsumer, Level, ActiveLow, ExclusiveAndWake, ,, ) Interrupt (ResourceConsumer, Level, ActiveLow, Exclusive, ,, )
{ {
0x0000002D, 0x0000002D,
} }
@ -124,23 +124,30 @@ It also adds the interrupt,
which comes from: which comes from:
``` ```
register "irq" = "ACPI_IRQ_WAKE_LEVEL_LOW(GPP_A21_IRQ)" register "irq" = "ACPI_IRQ_LEVEL_LOW(GPP_A21_IRQ)"
``` ```
The GPIO pin IRQ settings control the "Level", "ActiveLow", and The IRQ settings control the "Trigger" and "Polarity" settings seen above (level
"ExclusiveAndWake" settings seen above (level means it is a level-triggered means it is a level-triggered interrupt as opposed to
interrupt as opposed to edge-triggered; active low means the interrupt is edge-triggered; active low means the interrupt is triggered when the signal is
triggered when the signal is low). low).
Note that the ACPI_IRQ_WAKE_LEVEL_LOW macro informs the platform that the GPIO Also note that the IRQ names are SoC-specific, and you will need to
will be routed through SCI (ACPI's System Control Interrupt) for use as a wake
source. Also note that the IRQ names are SoC-specific, and you will need to
find the names in your SoC's header file. The ACPI_* macros are defined in find the names in your SoC's header file. The ACPI_* macros are defined in
``src/arch/x86/include/acpi/acpi_device.h``. ``src/arch/x86/include/acpi/acpi_device.h``.
Using a GPIO as an IRQ requires that it is configured in coreboot correctly. Using a GPIO as an IRQ requires that it is configured in coreboot correctly.
This is often done in a mainboard-specific file named ``gpio.c``. This is often done in a mainboard-specific file named ``gpio.c``.
AMD platforms don't have the ability to route GPIOs to the IO-APIC. Instead the
GPIO controller needs to be used directly. You can do this by setting the
`irq_gpio` register and using the `ACPI_GPIO_IRQ_X_X` macros.
i.e.,
```
register "irq_gpio" = "ACPI_GPIO_IRQ_EDGE_LOW(GPIO_40)"
```
### detect ### detect
The next register is: The next register is:
@ -180,6 +187,8 @@ through a GPE, #21 associated with DW0, which is set up in devicetree.cb from
this example. The "21" indicates GPP_X21, where GPP_X is mapped onto DW0 this example. The "21" indicates GPP_X21, where GPP_X is mapped onto DW0
elsewhere in the devicetree. elsewhere in the devicetree.
### device
The last bit of the definition of that device includes: The last bit of the definition of that device includes:
``` ```
@ -193,6 +202,65 @@ found on. In this example, this is I2C bus 0. This also determines the ACPI
"Scope" that the device names and methods will live under, in this case "Scope" that the device names and methods will live under, in this case
"\_SB.PCI0.I2C0". "\_SB.PCI0.I2C0".
## Wake sources
The ACPI spec defines two methods to describe how a device can wake the system.
Only one of these methods should be used, otherwise duplicate wake events will
be generated.
### Using GPEs as a wake source
The `wake` property specified above is used to tell the ACPI subsystem that the
device can use a GPE to wake the system. The OS can control whether to enable
or disable the wake source by unmasking/masking off the GPE.
The `GPIO` -> `GPE` mapping must be configured in firmware. On AMD platforms this is
generally done by a mainboard specific `gpio.c` file that defines the GPIO
using `PAD_SCI`. The `GPIO` -> `GPE` mapping is returned by the
`soc_get_gpio_event_table` method that is defined in the SoC specific `gpio.c`
file. On Intel platforms, you fill in the `pmc_gpe0_dw0`, `pmc_gpe0_dw1`, and
`pmc_gpe0_dw2` fields in the devicetree to map 3 GPIO communities to `tier-1`
GPEs (the rest are available as `tier-2` GPEs).
Windows has a large caveat when using this method. If you use the `gpio_irq`
property to define a `GpioInt` in the `_CRS`, and then use the `wake` property
to define a `GPE`, Windows will
[BSOD](https://github.com/MicrosoftDocs/windows-driver-docs/blob/staging/windows-driver-docs-pr/debugger/bug-check-0xa5--acpi-bios-error.md)
complaining about an invalid ACPI configuration.
> 0x1000D - A device used both GPE and GPIO interrupts, which is not supported.
In order to avoid this error, you should use the `irq` property instead. AMD
platforms don't support routing GPIOs to the IO-APIC, so this workaround isn't
feasible. The other option is to use a wake capable GPIO as described below.
### Using GPIO interrupts as a wake source
The `ACPI_IRQ_WAKE_{EDGE,LEVEL}_{LOW,HIGH}` macros can be used when setting the
`irq` or `gpio_irq` properties. This ends up setting `ExclusiveAndWake` or
`SharedAndWake` on the `Interrupt` or `GpioInt` ACPI resource.
This method has a few caveats:
* On Intel and AMD platforms the IO-APIC can't wake the system. This means using
the `ACPI_IRQ_WAKE_*` macros with the `irq` property won't actually wake the
system. Instead you need to use the `gpio_irq` property, or a `GPE` as
described above.
* The OS needs to know how to enable the `wake` bit on the GPIO. For linux this
means the platform specific GPIO controller driver must implement the
`irq_set_wake` callback. For AMD systems this wasn't
[implemented](https://github.com/torvalds/linux/commit/d62bd5ce12d79bcd6a6c3e4381daa7375dc21158)
until linux v5.15. If the controller doesn't define this callback, it's
possible for the firmware to manually set the `wake` bit on the GPIO. This is
often done in a mainboard-specific file named `gpio.c`. This is not
recommended because then it's not possible for the OS to disable the wake
source.
* As of
[linux v6.0-rc5](https://github.com/torvalds/linux/releases/tag/v6.0-rc5),
the ACPI subsystem doesn't take the interrupt `wake` bit into account when
deciding on which power state to put the device in before suspending the
system. This means that if you define a power resource for a device via
`has_power_resource`, `enable_gpio`, etc, then the linux kernel will place the
device into D3Cold. i.e., power off the device.
## Other auto-generated names ## Other auto-generated names
(see [ACPI specification (see [ACPI specification
@ -200,17 +268,19 @@ found on. In this example, this is I2C bus 0. This also determines the ACPI
for more details on ACPI methods) for more details on ACPI methods)
### _S0W (S0 Device Wake State) ### _S0W (S0 Device Wake State)
_S0W indicates the deepest S0 sleep state this device can wake itself from, \_S0W indicates the deepest S0 sleep state this device can wake itself from,
which in this case is ACPI_DEVICE_SLEEP_D3_HOT, representing _D3hot_. which in this case is `ACPI_DEVICE_SLEEP_D3_HOT`, representing _D3hot_.
D3Hot means the `PR3` power resources are still on and the device is still
responsive on the bus. For i2c devices this is generally the same state as `D0`.
### _PRW (Power Resources for Wake) ### \_PRW (Power Resources for Wake)
_PRW indicates the power resources and events required for wake. There are no \_PRW indicates the power resources and events required for wake. There are no
dependent power resources, but the GPE (GPE0_DW0_21) is mentioned here (0x15), dependent power resources, but the GPE (GPE0_DW0_21) is mentioned here (0x15),
as well as the deepest sleep state supporting waking the system (3), which is as well as the deepest sleep state supporting waking the system (3), which is
S3. S3.
### _STA (Status) ### \_STA (Status)
The _STA method is generated automatically, and its values, 0xF, indicates the The \_STA method is generated automatically, and its values, 0xF, indicates the
following: following:
Bit [0] Set if the device is present. Bit [0] Set if the device is present.
@ -218,8 +288,8 @@ following:
Bit [2] Set if the device should be shown in the UI. Bit [2] Set if the device should be shown in the UI.
Bit [3] Set if the device is functioning properly (cleared if device failed its diagnostics). Bit [3] Set if the device is functioning properly (cleared if device failed its diagnostics).
### _CRS (Current resource settings) ### \_CRS (Current resource settings)
The _CRS method is generated automatically, as the driver knows it is an I2C The \_CRS method is generated automatically, as the driver knows it is an I2C
controller, and so specifies how to configure the controller for proper controller, and so specifies how to configure the controller for proper
operation with the touchpad. operation with the touchpad.