The Linux kernel runtime D3 framework expects a PCIe device to have a power resource in order to be properly power-manageable. The _PR0/_PR3 values were pointing at the PEG0 Device, which is not a PowerResource, so this must have confused the RTD3 framework and RTD3 was not functional. Removing the _PR0/_PR3 fixes the problem. BUG=b:243888246 TEST=echo auto > /sys/bus/pci/devices/0000:01:00.0/power/control; sleep 10; echo on > /sys/bus/pci/devices/0000:01:00.0/power/control After this there are no longer errors seen in dmesg about failing to place the device into D0. Signed-off-by: Tim Wawrzynczak <twawrzynczak@chromium.org> Change-Id: I83fa1e5fabd3257b097c10e7a13c9861872685ea Reviewed-on: https://review.coreboot.org/c/coreboot/+/67212 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Cliff Huang <cliff.huang@intel.com> Reviewed-by: Tarun Tuli <taruntuli@google.com> Reviewed-by: Subrata Banik <subratabanik@google.com> Reviewed-by: Eric Lai <eric_lai@quanta.corp-partner.google.com>
425 lines
7.6 KiB
Plaintext
425 lines
7.6 KiB
Plaintext
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#include <device/pci_ids.h>
|
|
|
|
External (\_SB.PCI0.PMC.IPCS, MethodObj)
|
|
|
|
/* Voltage rail control signals */
|
|
#define GPIO_1V8_PWR_EN GPP_E18
|
|
#define GPIO_1V8_PG GPP_E20
|
|
#define GPIO_NV33_PWR_EN GPP_A21
|
|
#define GPIO_NV33_PG GPP_A22
|
|
#define GPIO_NVVDD_PWR_EN GPP_E0
|
|
#define GPIO_PEXVDD_PWR_EN GPP_E10
|
|
#define GPIO_PEXVDD_PG GPP_E17
|
|
#define GPIO_FBVDD_PWR_EN GPP_A19
|
|
#define GPIO_FBVDD_PG GPP_E4
|
|
|
|
#define GPIO_GPU_PERST_L GPP_B3
|
|
#define GPIO_GPU_ALLRAILS_PG GPP_E5
|
|
#define GPIO_GPU_NVVDD_EN GPP_A17
|
|
|
|
#define GC6_DEFER_TYPE_EXIT_GC6 3
|
|
|
|
/* 250ms in "Timer" units (i.e. 100ns increments) */
|
|
#define MIN_OFF_TIME_TIMERS 2500000
|
|
|
|
#define SRCCLK_DISABLE 0
|
|
#define SRCCLK_ENABLE 1
|
|
|
|
#define GPU_POWER_STATE_OFF 0
|
|
#define GPU_POWER_STATE_ON 1
|
|
|
|
/*
|
|
* For board revs 3 and later, the PG pin for the NVVDD VR moved from
|
|
* GPP_E16 to GPP_E3. To accommodate this, this DSDT contains a Name
|
|
* that the `variant.c` code will write the correct GPIO # to depending
|
|
* on the board rev, and we'll use that instead.
|
|
*/
|
|
/* Dynamically-assigned NVVDD PG GPIO, set in _INI in SSDT */
|
|
Name (NVPG, 0)
|
|
|
|
/* Optimus Power Control State */
|
|
Name (OPCS, OPTIMUS_POWER_CONTROL_DISABLE)
|
|
|
|
/* PCI configuration space Owner */
|
|
Name (PCIO, PCI_OWNER_DRIVER)
|
|
|
|
/* Saved PCI configuration space memory (VGA Buffer) */
|
|
Name (VGAB, Buffer (0xfb) { 0x00 })
|
|
|
|
/* Deferred GPU State */
|
|
Name (OPS0, OPTIMUS_CONTROL_NO_RUN_PS0)
|
|
|
|
/* GC6 Entry/Exit state */
|
|
Name (GC6E, GC6_STATE_EXITED)
|
|
|
|
/* Power State, GCOFF, GCON */
|
|
Name (GPPS, GPU_POWER_STATE_ON)
|
|
|
|
/* Defer GC6 entry / exit until D3-cold request */
|
|
Name (DFEN, 0)
|
|
/* Deferred GC6 Enter control */
|
|
Name (DFCI, 0)
|
|
/* Deferred GC6 Exit control */
|
|
Name (DFCO, 0)
|
|
/* GCOFF Timer */
|
|
Name (GCOT, 0)
|
|
|
|
#define PMC_SRCCLK_PIN 0x1
|
|
#define PMC_SRCCLK_ENABLE 0x1
|
|
#define PMC_SRCCLK_DISABLE 0x0
|
|
|
|
#define PMC_RP_IDX (1 << 27)
|
|
#define PMC_RP_ENABLE (1 << 27)
|
|
#define PMC_RP_DISABLE 0x0
|
|
/* Copy of LTR enable bit from PEG port */
|
|
Name (SLTR, 0)
|
|
|
|
/* Control the PCIe SRCCLK# for dGPU */
|
|
Method (SRCC, 1, Serialized)
|
|
{
|
|
If (!Arg0)
|
|
{
|
|
Local0 = PMC_SRCCLK_DISABLE
|
|
Local1 = PMC_RP_DISABLE
|
|
}
|
|
Else
|
|
{
|
|
Local0 = PMC_SRCCLK_ENABLE
|
|
Local1 = PMC_RP_ENABLE
|
|
}
|
|
|
|
\_SB.PCI0.PMC.IPCS (0xac, 0, 16, PMC_SRCCLK_PIN,
|
|
Local0, PMC_RP_IDX, Local1)
|
|
}
|
|
|
|
/* "GC6 In", i.e. GC6 Entry Sequence */
|
|
Method (GC6I, 0, Serialized)
|
|
{
|
|
GC6E = GC6_STATE_TRANSITION
|
|
|
|
/* Save the PEG port's LTR setting */
|
|
SLTR = LREN
|
|
|
|
/* Put PCIe link into L2/3 */
|
|
\_SB.PCI0.PEG0.DL23 ()
|
|
|
|
/* Wait for GPU to deassert its GPIO4, i.e. GPU_NVVDD_EN */
|
|
GPPL (GPIO_GPU_NVVDD_EN, 0, 20)
|
|
|
|
/* Deassert PG_GPU_ALLRAILS */
|
|
CTXS (GPIO_GPU_ALLRAILS_PG)
|
|
|
|
/* Ramp down PEXVDD */
|
|
CTXS (GPIO_PEXVDD_PWR_EN)
|
|
GPPL (GPIO_PEXVDD_PG, 0, 20)
|
|
Sleep (10)
|
|
|
|
/* Deassert EN_PPVAR_GPU_NVVDD */
|
|
CTXS (GPIO_NVVDD_PWR_EN)
|
|
GPPL (NVPG, 0, 20)
|
|
Sleep (2)
|
|
|
|
/* Assert GPU_PERST_L */
|
|
CTXS (GPIO_GPU_PERST_L)
|
|
|
|
/* Disable PCIe SRCCLK# */
|
|
SRCC (SRCCLK_DISABLE)
|
|
|
|
GC6E = GC6_STATE_ENTERED
|
|
}
|
|
|
|
/* "GC6 Out", i.e. GC6 Exit Sequence */
|
|
Method (GC6O, 0, Serialized)
|
|
{
|
|
GC6E = GC6_STATE_TRANSITION
|
|
|
|
/* Re-enable PCIe SRCCLK# */
|
|
SRCC (SRCCLK_ENABLE)
|
|
|
|
/* Deassert GPU_PERST_L */
|
|
STXS (GPIO_GPU_PERST_L)
|
|
|
|
/* Wait for GPU to assert GPU_NVVDD_EN */
|
|
GPPL (GPIO_GPU_NVVDD_EN, 1, 20)
|
|
|
|
/* Ramp up NVVDD */
|
|
STXS (GPIO_NVVDD_PWR_EN)
|
|
GPPL (NVPG, 1, 4)
|
|
|
|
/* Ramp up PEXVDD */
|
|
STXS (GPIO_PEXVDD_PWR_EN)
|
|
GPPL (GPIO_PEXVDD_PG, 1, 4)
|
|
|
|
/* Assert PG_GPU_ALLRAILS */
|
|
STXS (GPIO_GPU_ALLRAILS_PG)
|
|
|
|
/* Restore PCIe link back to L0 state */
|
|
\_SB.PCI0.PEG0.LD23 ()
|
|
|
|
/* Wait for dGPU to reappear on the bus */
|
|
Local0 = 50
|
|
While (NVID != PCI_VID_NVIDIA)
|
|
{
|
|
Stall (100)
|
|
Local0--
|
|
If (Local0 == 0)
|
|
{
|
|
Break
|
|
}
|
|
}
|
|
|
|
/* Restore the PEG LTR enable bit */
|
|
LREN = SLTR
|
|
|
|
/* Clear recoverable errors detected bit */
|
|
CEDR = 1
|
|
|
|
GC6E = GC6_STATE_EXITED
|
|
}
|
|
|
|
/* GCOFF exit sequence */
|
|
Method (PGON, 0, Serialized)
|
|
{
|
|
If (GPPS == GPU_POWER_STATE_ON)
|
|
{
|
|
Printf ("PGON: GPU already on")
|
|
Return
|
|
}
|
|
|
|
Local0 = Timer - GCOT
|
|
If (Local0 < MIN_OFF_TIME_TIMERS)
|
|
{
|
|
Local1 = (MIN_OFF_TIME_TIMERS - Local0) / 10000
|
|
Printf("Sleeping %o to ensure min GCOFF time", Local1)
|
|
Sleep (Local1)
|
|
}
|
|
|
|
/* Assert PERST# */
|
|
CTXS (GPIO_GPU_PERST_L)
|
|
|
|
/* Ramp up 1.8V rail */
|
|
STXS (GPIO_1V8_PWR_EN)
|
|
GPPL (GPIO_1V8_PG, 1, 20)
|
|
|
|
/* Ramp up NV33 rail */
|
|
STXS (GPIO_NV33_PWR_EN)
|
|
GPPL (GPIO_NV33_PG, 1, 20)
|
|
|
|
/* Ramp up NVVDD rail */
|
|
STXS (GPIO_NVVDD_PWR_EN)
|
|
GPPL (NVPG, 1, 5)
|
|
|
|
/* Ramp up PEXVDD rail */
|
|
STXS (GPIO_PEXVDD_PWR_EN)
|
|
GPPL (GPIO_PEXVDD_PG, 1, 5)
|
|
|
|
/* Ramp up FBVDD rail (active low) */
|
|
CTXS (GPIO_FBVDD_PWR_EN)
|
|
GPPL (GPIO_FBVDD_PG, 1, 5)
|
|
|
|
/* All rails are good */
|
|
STXS (GPIO_GPU_ALLRAILS_PG)
|
|
Sleep (1)
|
|
|
|
/* Deassert PERST# */
|
|
STXS (GPIO_GPU_PERST_L)
|
|
|
|
|
|
GC6E = GC6_STATE_EXITED
|
|
GPPS = GPU_POWER_STATE_ON
|
|
}
|
|
|
|
/* GCOFF entry sequence */
|
|
Method (PGOF, 0, Serialized)
|
|
{
|
|
If (GPPS == GPU_POWER_STATE_OFF)
|
|
{
|
|
Printf ("GPU already off")
|
|
Return
|
|
}
|
|
|
|
/* Assert PERST# */
|
|
CTXS (GPIO_GPU_PERST_L)
|
|
|
|
/* All rails are about to go down */
|
|
CTXS (GPIO_GPU_ALLRAILS_PG)
|
|
Sleep (1)
|
|
|
|
/* Ramp down FBVDD (active-low) and let rail discharge to <10% */
|
|
STXS (GPIO_FBVDD_PWR_EN)
|
|
GPPL (GPIO_FBVDD_PG, 0, 20)
|
|
|
|
/* Ramp down PEXVDD and let rail discharge to <10% */
|
|
CTXS (GPIO_PEXVDD_PWR_EN)
|
|
GPPL (GPIO_PEXVDD_PG, 0, 20)
|
|
Sleep (10)
|
|
|
|
/* Ramp down NVVDD and let rail discharge to <10% */
|
|
CTXS (GPIO_NVVDD_PWR_EN)
|
|
GPPL (NVPG, 0, 20)
|
|
Sleep (2)
|
|
|
|
/* Ramp down NV33 and let rail discharge to <10% */
|
|
CTXS (GPIO_NV33_PWR_EN)
|
|
GPPL (GPIO_NV33_PG, 0, 20)
|
|
Sleep (4)
|
|
|
|
/* Ramp down 1.8V */
|
|
CTXS (GPIO_1V8_PWR_EN)
|
|
GPPL (GPIO_1V8_PG, 0, 20)
|
|
|
|
GCOT = Timer
|
|
|
|
GPPS = GPU_POWER_STATE_OFF
|
|
}
|
|
|
|
/* GCOFF Out, i.e. full power-on sequence */
|
|
Method (GCOO, 0, Serialized)
|
|
{
|
|
SRCC (SRCCLK_ENABLE)
|
|
PGON ()
|
|
\_SB.PCI0.PEG0.LD23 ()
|
|
|
|
/* Wait for dGPU to reappear on the bus */
|
|
Local0 = 50
|
|
While (NVID != PCI_VID_NVIDIA)
|
|
{
|
|
Stall (100)
|
|
Local0--
|
|
If (Local0 == 0)
|
|
{
|
|
Break
|
|
}
|
|
}
|
|
|
|
/* Restore the PEG LTR enable bit */
|
|
LREN = SLTR
|
|
|
|
/* Clear recoverable errors detected bit */
|
|
CEDR = 1
|
|
|
|
/* Restore the PEG LTR enable bit */
|
|
LREN = SLTR
|
|
|
|
/* Clear recoverable errors detected bit */
|
|
CEDR = 1
|
|
}
|
|
|
|
/* GCOFF In, i.e. full power-off sequence */
|
|
Method (GCOI, 0, Serialized)
|
|
{
|
|
/* Save the PEG port's LTR setting */
|
|
SLTR = LREN
|
|
|
|
\_SB.PCI0.PEG0.DL23 ()
|
|
PGOF ()
|
|
SRCC (SRCCLK_DISABLE)
|
|
}
|
|
|
|
/* Handle deferred GC6 vs. poweron request */
|
|
Method (NPON, 0, Serialized)
|
|
{
|
|
If (DFEN == GC6_DEFER_ENABLE)
|
|
{
|
|
If (DFCO == GC6_DEFER_TYPE_EXIT_GC6)
|
|
{
|
|
GC6O ()
|
|
}
|
|
|
|
DFEN = GC6_DEFER_DISABLE
|
|
}
|
|
Else
|
|
{
|
|
GCOO ()
|
|
}
|
|
}
|
|
|
|
/* Handle deferred GC6 vs. poweroff request */
|
|
Method (NPOF, 0, Serialized)
|
|
{
|
|
If (DFEN == GC6_DEFER_ENABLE)
|
|
{
|
|
/* Deferred GC6 entry */
|
|
If (DFCI == NVJT_GPC_EGNS || DFCI == NVJT_GPC_EGIS)
|
|
{
|
|
GC6I ()
|
|
}
|
|
|
|
DFEN = GC6_DEFER_DISABLE
|
|
}
|
|
Else
|
|
{
|
|
GCOI ()
|
|
}
|
|
}
|
|
|
|
Method (_ON, 0, Serialized)
|
|
{
|
|
PGON ()
|
|
}
|
|
|
|
Method (_OFF, 0, Serialized)
|
|
{
|
|
PGOF ()
|
|
}
|
|
|
|
/* Put device into D0 */
|
|
Method (_PS0, 0, NotSerialized)
|
|
{
|
|
If (OPS0 == OPTIMUS_CONTROL_RUN_PS0)
|
|
{
|
|
/* Restore PCI config space */
|
|
If (PCIO == PCI_OWNER_SBIOS)
|
|
{
|
|
VGAR = VGAB
|
|
}
|
|
|
|
/* Poweron or deferred GC6 exit */
|
|
NPON ()
|
|
|
|
OPS0 = OPTIMUS_CONTROL_NO_RUN_PS0
|
|
}
|
|
}
|
|
|
|
/* Put device into D3 */
|
|
Method (_PS3, 0, NotSerialized)
|
|
{
|
|
If (OPCS == OPTIMUS_POWER_CONTROL_ENABLE)
|
|
{
|
|
/* Save PCI config space to ACPI buffer */
|
|
If (PCIO == PCI_OWNER_SBIOS)
|
|
{
|
|
VGAB = VGAR
|
|
}
|
|
|
|
/* Poweroff or deferred GC6 entry */
|
|
NPOF ()
|
|
|
|
/* Because _PS3 ran NPOF, _PS0 must run NPON */
|
|
OPS0 = OPTIMUS_CONTROL_RUN_PS0
|
|
|
|
/* OPCS is one-shot, so reset it */
|
|
OPCS = OPTIMUS_POWER_CONTROL_DISABLE
|
|
}
|
|
}
|
|
|
|
Method (PSTA, 0, Serialized)
|
|
{
|
|
If (GC6E == GC6_STATE_EXITED &&
|
|
\_SB.PCI0.GTXS(GPIO_GPU_ALLRAILS_PG) == 1)
|
|
{
|
|
Return (1)
|
|
}
|
|
Else
|
|
{
|
|
Return (0)
|
|
}
|
|
}
|
|
|
|
Method (_STA, 0, Serialized)
|
|
{
|
|
Return (0xF)
|
|
}
|