From 865292a883f6bb63a2efc9c2e9a9dd43887edd91 Mon Sep 17 00:00:00 2001 From: Tim Crawford Date: Mon, 22 Nov 2021 08:01:51 -0700 Subject: [PATCH] [WIP] drivers/gfx/nvidia: ACPI rewrite Begin rewriting the ACPI support according to the Design Guide. Partially implements Low Power States and GPU Boost methods. Change-Id: I119f3206685ad337dcbb73d55cc807d00d5659fb Signed-off-by: Tim Crawford --- src/drivers/gfx/nvidia/acpi/boost.asl | 81 +++++ src/drivers/gfx/nvidia/acpi/gpu.asl | 283 +++++++----------- .../gfx/nvidia/acpi/low_power_states.asl | 112 +++++++ 3 files changed, 300 insertions(+), 176 deletions(-) create mode 100644 src/drivers/gfx/nvidia/acpi/boost.asl create mode 100644 src/drivers/gfx/nvidia/acpi/low_power_states.asl diff --git a/src/drivers/gfx/nvidia/acpi/boost.asl b/src/drivers/gfx/nvidia/acpi/boost.asl new file mode 100644 index 0000000000..98abc522f7 --- /dev/null +++ b/src/drivers/gfx/nvidia/acpi/boost.asl @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +// NVIDIA GPU Boost for Notebook and All-In-One-Projects + +#define GPS_FUNC_SUPPORT 0 +#define GPS_FUNC_GETOBJBYTYPE 16 +#define GPS_FUNC_GETALLOBJS 17 +#define GPS_FUNC_GETCALLBACKS 19 +#define GPS_FUNC_PCONTROL 28 +#define GPS_FUNC_PSHARESTATUS 32 +#define GPS_FUNC_PSHAREPARAMS 42 + +Method (NVGB, 2, NotSerialized) +{ + Printf("GPS {") + + Switch (ToInteger(Arg0)) { + // Bit list of supported functions + Case (GPS_FUNC_SUPPORT) { + Printf(" GPS_FUNC_SUPPORT") + // Functions supported: 0, 32, 42 + Local0 = Buffer () {0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00} + } + + // Get current platform status, thermal budget + Case (GPS_FUNC_PSHARESTATUS) { + Printf(" GPS_FUNC_PSHARESTATUS") + Local0 = Buffer (4) { 0 } + } + + // Get GPU Boost platform parameters + Case (GPS_FUNC_PSHAREPARAMS) { + Printf(" GPS_FUNC_PSHAREPARAMS") + CreateField (Arg1, 0, 3, QTYP) // Query Type + CreateField (Arg1, 8, 1, GTMP) // GPU temperature status + CreateField (Arg1, 9, 1, CTMP) // CPU temperature status + + Local0 = Buffer (36) { 0 } + CreateDWordField (Local0, 0, STAT) // Status + CreateDWordField (Local0, 4, VERS) // Version + CreateDWordField (Local0, 8, TGPU) // GPU temperature (C) + CreateDWordField (Local0, 12, PDTS) // CPU package temperature (C) + + VERS = 0x00010000 + STAT = QTYP + + Switch (ToInteger(QTYP)) { + // Get current status + Case (0) { + // TGPU must be 0. + } + + // Get supported fields + Case (1) { + STAT |= 0x100 + // TGPU must be 0. + } + + // Get current operating limits + Case (2) { + // GPU temperature status must be 1. + STAT |= 0x100 + // TGPU should be 0. GPU will use its own default. + } + + Default { + Printf(" Unsupported Query Type: %o", ToInteger(QTYP)) + Local0 = NVIDIA_ERROR_UNSUPPORTED + } + } + } + + Default { + Printf(" Unsupported GPS_FUNC: %o", ToInteger(Arg0)) + Local0 = NVIDIA_ERROR_UNSUPPORTED + } + } + + Printf("}") + Return(Local0) +} diff --git a/src/drivers/gfx/nvidia/acpi/gpu.asl b/src/drivers/gfx/nvidia/acpi/gpu.asl index 8c346fdd5b..19971e445e 100644 --- a/src/drivers/gfx/nvidia/acpi/gpu.asl +++ b/src/drivers/gfx/nvidia/acpi/gpu.asl @@ -1,202 +1,133 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -Device (\_SB.PCI0.PEGP) { +#define NVIDIA_ERROR_UNSPECIFIED 0x80000001 +#define NVIDIA_ERROR_UNSUPPORTED 0x80000002 + +#define NBCI_DSM_GUID "D4A50B75-65C7-46F7-BFB7-41514CEA0244" +#define NBCI_REVISION_ID 0x102 + +#define GPS_DSM_GUID "A3132D01-8CDA-49BA-A52E-BC9D46DF6B81" +#define GPS_REVISION_ID 0x200 + +#define JT_DSM_GUID "CBECA351-067B-4924-9CBD-B46B00B86F34" +#define JT_REVISION_ID 0x200 + +#define NVOP_DSM_GUID "A486D8F8-0BDA-471B-A72B-6042A6B5BEE0" +#define NVOP_REVISION_ID 0x100 + +Device (\_SB.PCI0.PEG0) +{ Name (_ADR, CONFIG_DRIVERS_GFX_NVIDIA_BRIDGE << 16) PowerResource (PWRR, 0, 0) { Name (_STA, 1) - Method (_ON) { - Debug = "PEGP.PWRR._ON" - If (_STA != 1) { - \_SB.PCI0.PEGP.DEV0._ON () - _STA = 1 - } + Method (_ON) + { + _STA = 1 } - Method (_OFF) { - Debug = "PEGP.PWRR._OFF" - If (_STA != 0) { - \_SB.PCI0.PEGP.DEV0._OFF () - _STA = 0 - } + Method (_OFF) + { + _STA = 0 } } - Name (_PR0, Package () { \_SB.PCI0.PEGP.PWRR }) - Name (_PR2, Package () { \_SB.PCI0.PEGP.PWRR }) - Name (_PR3, Package () { \_SB.PCI0.PEGP.PWRR }) + Name (_PR0, Package () { PWRR }) + Name (_PR3, Package () { PWRR }) } -Device (\_SB.PCI0.PEGP.DEV0) { +Device (\_SB.PCI0.PEG0.DGPU) +{ Name(_ADR, 0x00000000) - Name (_STA, 0xF) - Name (LTRE, 0) - // Memory mapped PCI express registers - // Not sure what this stuff is, but it is used to get into GC6 - // TODO: use GPU config to generate address - OperationRegion (RPCX, SystemMemory, CONFIG_ECAM_MMCONF_BASE_ADDRESS + 0x8000, 0x1000) - Field (RPCX, ByteAcc, NoLock, Preserve) { - PVID, 16, - PDID, 16, - CMDR, 8, - Offset (0x19), - PRBN, 8, - Offset (0x84), - D0ST, 2, - Offset (0xAA), - CEDR, 1, - Offset (0xAC), - , 4, - CMLW, 6, - Offset (0xB0), - ASPM, 2, - , 2, - P0LD, 1, - RTLK, 1, - Offset (0xC9), - , 2, - LREN, 1, - Offset (0x11A), - , 1, - VCNP, 1, - Offset (0x214), - Offset (0x216), - P0LS, 4, - Offset (0x248), - , 7, - Q0L2, 1, - Q0L0, 1, - Offset (0x504), - Offset (0x506), - PCFG, 2, - Offset (0x508), - TREN, 1, - Offset (0xC20), - , 4, - P0AP, 2, - Offset (0xC38), - , 3, - P0RM, 1, - Offset (0xC74), - P0LT, 4, - Offset (0xD0C), - , 20, - LREV, 1 - } + // GPU Power + Name (GPWR, 0) - Method (_ON) { - Debug = "PEGP.DEV0._ON" + // GCx State + Name (GCST, 0) - If (_STA != 0xF) { - Debug = " If DGPU_PWR_EN low" - If (! GTXS (DGPU_PWR_EN)) { - Debug = " DGPU_PWR_EN high" - STXS (DGPU_PWR_EN) + // For supporting Hybrid Graphics, the package refers to the PCIe controller + // itself, which leverages GC6 Control methods under the dGPU namespace. + Name (_PR0, Package() { \_SB.PCI0.PEG0.PWRR }) + Name (_PR3, Package() { \_SB.PCI0.PEG0.PWRR }) - Debug = " Sleep 16" - Sleep (16) - } - - Debug = " DGPU_RST_N high" - STXS(DGPU_RST_N) - - Debug = " Sleep 10" - Sleep (10) - - Debug = " Q0L0 = 1" - Q0L0 = 1 - - Debug = " Sleep 16" - Sleep (16) - - Debug = " While Q0L0" - Local0 = 0 - While (Q0L0) { - If ((Local0 > 4)) { - Debug = " While Q0L0 timeout" - Break - } - - Sleep (16) - Local0++ - } - - Debug = " P0RM = 0" - P0RM = 0 - - Debug = " P0AP = 0" - P0AP = 0 - - Debug = Concatenate(" LREN = ", ToHexString(LTRE)) - LREN = LTRE - - Debug = " CEDR = 1" - CEDR = 1 - - Debug = " CMDR |= 7" - CMDR |= 7 - - Debug = " _STA = 0xF" - _STA = 0xF + Method (_STA) + { + /* + * Only return "On" when: + * - GPU power is good + * - GPU has completed return to GC0 + * + * In all other cases, return "Off". + */ + If ((GPWR == 1) && (GCST == 0)) { + Return (0xF) + } Else { + Return (0) } } - Method (_OFF) { - Debug = "PEGP.DEV0._OFF" + Method (_ON) + { + Printf("_ON {") + Printf(" Enable GPU power") + STXS(DGPU_PWR_EN) + Sleep(10) - If (_STA != 0x5) { - Debug = Concatenate(" LTRE = ", ToHexString(LREN)) - LTRE = LREN + Printf(" Take GPU out of reset") + STXS(DGPU_RST_N) + Sleep(10) - Debug = " Q0L2 = 1" - Q0L2 = 1 - - Debug = " Sleep 16" - Sleep (16) - - Debug = " While Q0L2" - Local0 = Zero - While (Q0L2) { - If ((Local0 > 4)) { - Debug = " While Q0L2 timeout" - Break - } - - Sleep (16) - Local0++ - } - - Debug = " P0RM = 1" - P0RM = 1 - - Debug = " P0AP = 3" - P0AP = 3 - - Debug = " Sleep 10" - Sleep (10) - - Debug = " DGPU_RST_N low" - CTXS(DGPU_RST_N) - - Debug = " While DGPU_GC6 low" - Local0 = Zero - While (! GRXS(DGPU_GC6)) { - If ((Local0 > 4)) { - Debug = " While DGPU_GC6 low timeout" - - Debug = " DGPU_PWR_EN low" - CTXS (DGPU_PWR_EN) - Break - } - - Sleep (16) - Local0++ - } - - Debug = " _STA = 0x5" - _STA = 0x5 - } + GPWR = 1 + Printf("} _ON") } + + Method (_OFF) + { + Printf("_OFF {") + Printf(" Put GPU in reset") + CTXS(DGPU_RST_N) + Sleep(10) + + Printf(" Disable GPU power") + CTXS(DGPU_PWR_EN) + Sleep(10) + + GPWR = 0 + Printf("} _OFF") + } + + Method (_PS0) + { + // XGXS, XGIS, XCLM + } + + Method (_PS3) + { + // EGNS, EGIS, EGIN + } + + Method (_DSM, 4, NotSerialized) + { + // NVIDIA GPU Boost + If (Arg0 == ToUUID(GPS_DSM_GUID)) { + If (Arg1 <= GPS_REVISION_ID) { + Return(NVGB(Arg2, Arg3)) + } + } + + // NVIDIA Low Power States + If (Arg0 == ToUUID(JT_DSM_GUID)) { + If (Arg1 <= JT_REVISION_ID) { + Return(NVJT(Arg2, Arg3)) + } + } + + Printf("Unsupported GUID") + Return(NVIDIA_ERROR_UNSUPPORTED) + } + + #include "boost.asl" + #include "low_power_states.asl" } diff --git a/src/drivers/gfx/nvidia/acpi/low_power_states.asl b/src/drivers/gfx/nvidia/acpi/low_power_states.asl new file mode 100644 index 0000000000..3df57118a3 --- /dev/null +++ b/src/drivers/gfx/nvidia/acpi/low_power_states.asl @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +// NVIDIA Low Power States + +#define JT_FUNC_SUPPORT 0 +#define JT_FUNC_CAPS 1 +#define JT_FUNC_POWERCONTROL 3 +#define JT_FUNC_PLATPOLICY 4 + +Method (NVJT, 2, NotSerialized) +{ + Printf("NVJT {") + Switch (ToInteger(Arg0)) { + Case (JT_FUNC_SUPPORT) { + Printf(" JT_FUNC_SUPPORT"); + // Functions supported: 0, 1, 3, 4 + Local0 = Buffer() { 0x1B, 0, 0, 0 } + } + + Case (JT_FUNC_CAPS) { + Printf(" JT_FUNC_CAPS"); + Local0 = Buffer(4) { 0, 0, 0, 0 } + + // G-SYNC NVSR Power Features + CreateField (Local0, 0, 1, JTEN) + JTEN = 0 + + // NVSR + CreateField (Local0, 1, 2, NVSE) + NVSE = 1 + + // Panel Power Rail + CreateField (Local0, 3, 2, PPR) + PPR = 2 + + // Self-Refresh Control (SRC) Power Rail + CreateField (Local0, 5, 1, SRPR) + SRPR = 0 + + // FB Power Rail + CreateField (Local0, 6, 2, FBPR) + FBPR = 0 + + // GPU Power Rail + CreateField (Local0, 8, 2, GPR) + GPR = 0 + + // GC6 ROM + CreateField (Local0, 10, 1, GCR) + GCR = 0 + + // Panic Trap Handler + CreateField (Local0, 11, 1, PTH) + PTH = 1 + + // Supports Notify + CreateField (Local0, 12, 1, NOTS) + NOTS = 0 + + // MS Hybrid Support + CreateField (Local0, 13, 1, MHYB) + MHYB = 1 + + // Root Port Control + CreateField (Local0, 14, 1, RPC) + RPC = 1 + + // GC6 Version + CreateField (Local0, 15, 2, GC6V) + GC6V = 2 + + // GC6 Exit ISR Support + CreateField (Local0, 17, 1, GEI) + GEI = 0 + + // GC6 Self Wakeup Support + CreateField (Local0, 18, 1, GSW) + GSW = 0 + + // Maximum Revision Supported + CreateField (Local0, 20, 16, MXRV) + MXRV = JT_REVISION_ID + } + + Case (JT_FUNC_POWERCONTROL) { + Printf(" JT_FUNC_POWERCONTROL: Unimplemented!"); + // TODO + Local0 = NVIDIA_ERROR_UNSUPPORTED + } + + Case (JT_FUNC_PLATPOLICY) { + Printf(" JT_FUNC_PLATPOLICY"); + //CreateField (Arg1, 2, 1, AUD) // Azalia Audio Device + //CreateField (Arg1, 3, 1, ADM) // Audio Disable Mask + //CreateField (Arg1, 4, 4, DGS) // Driver expected State Mask + + // TODO: Save policy settings to NV CMOS? + + Local0 = Buffer(4) { 0, 0, 0, 0 } + //CreateField (Local0, 2, 1, AUD) // Audio Device status + //CreateField (Local0, 4, 3, GRE) // SBIOS requested GPU state + } + + Default { + Printf(" Unsupported JT_FUNC: %o", ToInteger(Arg0)) + Local0 = NVIDIA_ERROR_UNSUPPORTED + } + } + + Printf("}") + Return(Local0) +}