Compare commits

...

3 Commits

Author SHA1 Message Date
2d743165e7 drivers/gfx/nvidia: acpi: Skeleton code for NBCI
Signed-off-by: Tim Crawford <tcrawford@system76.com>
Change-Id: I5fbc8e1480670457586885c6099c19d73ca06c45
2021-12-21 13:32:33 -07:00
75468a84c0 drivers/gfx/nvidia: Misc fixes, some debugging
Change-Id: I072cd3db5859331a036ce7963a3607a56f53f37b
Signed-off-by: Tim Crawford <tcrawford@system76.com>
2021-12-21 12:10:57 -07:00
865292a883 [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 <tcrawford@system76.com>
2021-12-21 12:10:57 -07:00
5 changed files with 547 additions and 173 deletions

View File

@ -0,0 +1,37 @@
/* SPDX-License-Identifier: GPL-2.0-only */
// NVIDIA Advanced Optimus
#define NVOP_FUNC_SUPPORT 0
#define NVOP_FUNC_DISPLAYSTATUS 5
#define NVOP_FUNC_MDTL 6
#define NVOP_FUNC_GETOBJBYTYPE 16
#define NVOP_FUNC_GETALLOBJS 17
#define NVOP_FUNC_OPTIMUSCAPS 26
#define NVOP_FUNC_OPTIMUSFLAGS 27
Method (NVOP, 2, Serialized)
{
Printf("NVOP {")
Local0 = NVIDIA_ERROR_UNSUPPORTED
Switch (ToInteger(Arg0)) {
Case (NVOP_FUNC_SUPPORT) {
}
Case (NVOP_FUNC_OPTIMUSCAPS) {
CreateField (Arg1, 0, 1, FLGS) // Flag updates
CreateField (Arg1, 1, 1, PCOT) // PCIe Configuration Space Owner Target
CreateField (Arg1, 2, 1, PCOW) // PCIe Configuration Space Owner Write
CreateField (Arg1, 24, 2, OPCE) // Optimus Power Control Enable
}
Default {
Printf(" Unsupported NVOP_FUNC: %o", ToInteger(Arg0))
Local0 = NVIDIA_ERROR_UNSUPPORTED
}
}
Printf("} NVOP")
Return(Local0)
}

View File

@ -0,0 +1,83 @@
/* 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 (GPS, 2, Serialized)
{
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: %o", ToHexString(Arg1))
Local0 = Buffer (4) { 0 }
}
// Get GPU Boost platform parameters
Case (GPS_FUNC_PSHAREPARAMS) {
Printf(" GPS_FUNC_PSHAREPARAMS: %o", ToHexString(Arg1))
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
Printf(" Query Type = %o", ToInteger(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("} GPS")
Return(Local0)
}

View File

@ -1,202 +1,197 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* 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 0x103
#define NVOP_DSM_GUID "A486D8F8-0BDA-471B-A72B-6042A6B5BEE0"
#define NVOP_REVISION_ID 0x100
// 00:01.0
Device (\_SB.PCI0.PEG0)
{
Name (_ADR, CONFIG_DRIVERS_GFX_NVIDIA_BRIDGE << 16) Name (_ADR, CONFIG_DRIVERS_GFX_NVIDIA_BRIDGE << 16)
PowerResource (PWRR, 0, 0) { PowerResource (PWRR, 0, 0) {
Name (_STA, 1) Name (_STA, 1)
Method (_ON) { Method (_ON)
Debug = "PEGP.PWRR._ON" {
If (_STA != 1) { Printf("PEG0._ON {")
\_SB.PCI0.PEGP.DEV0._ON () // TODO: Check for deferred GCx action
_STA = 1 \_SB.PCI0.PEG0.DGPU._ON()
} _STA = 1
Printf("} PEG0._ON")
} }
Method (_OFF) { Method (_OFF)
Debug = "PEGP.PWRR._OFF" {
If (_STA != 0) { Printf("PEG0._OFF {")
\_SB.PCI0.PEGP.DEV0._OFF () // TODO: Check for deferred GCx action
_STA = 0 \_SB.PCI0.PEG0.DGPU._OFF()
} _STA = 0
Printf("} PEG0._OFF")
} }
} }
Name (_PR0, Package () { \_SB.PCI0.PEGP.PWRR }) Name (_PR0, Package () { PWRR })
Name (_PR2, Package () { \_SB.PCI0.PEGP.PWRR }) Name (_PR2, Package () { PWRR })
Name (_PR3, Package () { \_SB.PCI0.PEGP.PWRR }) Name (_PR3, Package () { PWRR })
} }
Device (\_SB.PCI0.PEGP.DEV0) { // 01:00.0
Device (\_SB.PCI0.PEG0.DGPU)
{
Name(_ADR, 0x00000000) Name(_ADR, 0x00000000)
Name (_STA, 0xF)
Name (LTRE, 0)
// Memory mapped PCI express registers Name (GPWR, 0) // GPU Power
// Not sure what this stuff is, but it is used to get into GC6 Name (GCST, 6) // GCx State
// TODO: use GPU config to generate address
OperationRegion (RPCX, SystemMemory, CONFIG_ECAM_MMCONF_BASE_ADDRESS + 0x8000, 0x1000) Name (DPC, 0) // Deferred power control
Field (RPCX, ByteAcc, NoLock, Preserve) { Name (DPCX, 0) // Deferred power control on exit
PVID, 16,
PDID, 16,
CMDR, 8, Name (NVID, 0x00000000)
Offset (0x19),
PRBN, 8, OperationRegion (PCIM, SystemMemory, 0x0E010000, 0xF0)
Offset (0x84), Field (PCIM, AnyAcc, Lock, Preserve)
D0ST, 2, {
Offset (0xAA), Offset(0x2c),
CEDR, 1, SSID, 32,
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
} }
Method (_ON) { // For supporting Hybrid Graphics, the package refers to the PCIe controller
Debug = "PEGP.DEV0._ON" // itself, which leverages GC6 Control methods under the dGPU namespace.
Name (_PR0, Package() { \_SB.PCI0.PEG0 })
Name (_PR3, Package() { \_SB.PCI0.PEG0 })
If (_STA != 0xF) { Method (_STA)
Debug = " If DGPU_PWR_EN low" {
If (! GTXS (DGPU_PWR_EN)) { Printf("DGPU._STA")
Debug = " DGPU_PWR_EN high" /*
STXS (DGPU_PWR_EN) * Only return "On" when:
* - GPU power is good
Debug = " Sleep 16" * - GPU has completed return to GC0
Sleep (16) *
} * In all other cases, return "Off".
*/
Debug = " DGPU_RST_N high" If ((GPWR == 1) && (GCST == 0)) {
STXS(DGPU_RST_N) Return (0xF)
} Else {
Debug = " Sleep 10" Return (0)
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 (_OFF) { Method (_ON)
Debug = "PEGP.DEV0._OFF" {
Printf("DGPU._ON {")
Printf(" Enable GPU power")
STXS(DGPU_PWR_EN)
Sleep(10)
If (_STA != 0x5) { Printf(" Take GPU out of reset")
Debug = Concatenate(" LTRE = ", ToHexString(LREN)) STXS(DGPU_RST_N)
LTRE = LREN Sleep(10)
Debug = " Q0L2 = 1" GPWR = 1
Q0L2 = 1 GCST = 0
Debug = " Sleep 16" /*
Sleep (16) // TODO: Actually check link status
Printf("Wait for PCIe link")
Sleep(100)
Debug = " While Q0L2" Printf("Restore SSID: %o", NVID)
Local0 = Zero SSID = NVID
While (Q0L2) { */
If ((Local0 > 4)) {
Debug = " While Q0L2 timeout"
Break
}
Sleep (16) Printf("} DGPU._ON")
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
}
} }
Method (_OFF)
{
Printf("DGPU._OFF {")
/*
Printf("Save SSID: %o", SSID)
NVID = SSID
// TODO: Actually check link status
Printf("Wait for PCIe link")
Sleep(100)
*/
Printf("DGPU._OFF {")
Printf(" Put GPU in reset")
CTXS(DGPU_RST_N)
Sleep(10)
Printf(" Disable GPU power")
CTXS(DGPU_PWR_EN)
GPWR = 0
GCST = 6
Printf("} DGPU._OFF")
}
Method (_PS0)
{
// XGXS, XGIS, XCLM
Printf("_PS0 {}")
}
Method (_PS3)
{
// EGNS, EGIS, EGIN
Printf("_PS3 {}")
}
Method (_DSM, 4, Serialized)
{
// Notebook Common Interface
If (Arg0 == ToUUID(NBCI_DSM_GUID)) {
Printf("NBCI_DSM_GUID")
If (Arg1 <= NBCI_REVISION_ID) {
Printf(" TODO: Unimplemented!")
}
}
// NVIDIA GPU Boost
If (Arg0 == ToUUID(GPS_DSM_GUID)) {
Printf("GPS_DSM_GUID")
If (Arg1 <= GPS_REVISION_ID) {
Return(GPS(Arg2, Arg3))
}
}
// NVIDIA Low Power States
If (Arg0 == ToUUID(JT_DSM_GUID)) {
Printf("JT_DSM_GUID")
If (Arg1 <= JT_REVISION_ID) {
Return(NVJT(Arg2, Arg3))
}
}
// Advanced Optimus
If (Arg0 == ToUUID(NVOP_DSM_GUID)) {
Printf("NVOP_DSM_GUID")
If (Arg1 <= NVOP_REVISION_ID) {
Printf(" TODO: Unimplemented!")
}
}
Printf("Unsupported GUID: %o", ToHexString(Arg0))
Return(NVIDIA_ERROR_UNSUPPORTED)
}
#include "boost.asl"
#include "low_power_states.asl"
} }

View File

@ -0,0 +1,169 @@
/* 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, Serialized)
{
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 }
Local0 = Buffer() { 0x13, 0, 0, 0 }
}
Case (JT_FUNC_CAPS) {
Printf(" JT_FUNC_CAPS");
Local0 = Buffer(4) { 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, 12, MXRV)
MXRV = JT_REVISION_ID
}
Case (JT_FUNC_POWERCONTROL) {
Printf(" JT_FUNC_POWERCONTROL: %o", ToHexString(Arg1));
// TODO
Local0 = NVIDIA_ERROR_UNSUPPORTED
/*
CreateField (Arg1, 0, 3, GPC) // GPU Power Control
CreateField (Arg1, 3, 1, GGP) // Global GPU Power
CreateField (Arg1, 4, 1, PPC) // Panel Power Control
CreateField (Arg1, 6, 2, NOC) // Notify on complete
CreateField (Arg1, 8, 2, PRGX) // PCIe Root Power GC6 Exit Sequence
CreateField (Arg1, 10, 2, PRGE) // PCIe Root Power GC6 Entry Sequence
CreateField (Arg1, 12, 1, PRPC) // Poll for Root Port Completion
CreateField (Arg1, 13, 1, PLON) // PCIe Root Port Control
CreateField (Arg1, 14, 2, DFGC) // Defer GC6 Enter/Exit until D3cold
CreateField (Arg1, 16, 3, GPCX) // Deferred GC6 Exit Control
CreateField (Arg1, 19, 1, EGEI) // Enable GC6 Exit ISR
CreateField (Arg1, 20, 2, PLCM) // PCIe Root Port Control Method for PLON
Local0 = Buffer(4) {0, 0, 0, 0}
CreateField (Local0, 0, 3, GCS) // GC State
CreateField (Local0, 3, 1, GPS) // GPU Power Status
CreateField (Local0, 7, 1, PSS) // Panel and SRC State
*/
/*
* DFGC
* 0: Perform request immediately
* 1: Defer GPC and GPCX to be processed when setting Device Power State
* 2: Clear any pending deferred requests
*/
/*
If (DFGC == 2) {
DPC = 0
DPCX = 0
}
*/
/*
* GPC
* 0 GSS) Get current GPU GCx Sleep Status
* 1 EGNS: Entery GC6 only. No SMI trap, No Self-Refresh. Panel
* and GPU will be powred down as normal. FB will remain powered.
* 2 EGIS: Enter GC6, keep Panel in Self-Refresh. Enable SMI trap on
* VGA I/O regiters. Control of screen is transitioned to the SRC and
* then the GPU is powered down. Panel and FB remain powered while
* the GPU is off.
* 3 XGXS: Exit GC6. Exit Panel Self-Refresh (Sparse). GPU is powered on.
* Disable SMI traps.
* 4 XGIS: Exit GC6 for Self-Refresh Update (Burst). GPU is powered on, but
* the SRC continues to retain control of screen refresh, while the
* GPU sends an update to SRC for display. Disable SMI traps.
* 5 EGIN: Enter GC6, keep Pnael in Self-Refresh. No SMI trap on VGA I/O
* registers. Control of screen is transitioned to SRC and then
* GPU is powred down. Panel and FB remain powered while the GPU is off.
* 6 XCLM: Trigger GPU_EVENT only. GPU_EVENT would be assered and de-asserted,
* regardless of GPU power state, without waiting for any GPU-side
* signaling. No change in GPU power state is made. SMI traps disabled.
*/
}
Case (JT_FUNC_PLATPOLICY) {
Printf(" JT_FUNC_PLATPOLICY: %o", ToHexString(Arg1));
//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("} NVJT")
Return(Local0)
}

View File

@ -0,0 +1,90 @@
/* SPDX-License-Identifier: GPL-2.0-only */
// Notebook Common Interface
#define NBCI_FUNC_SUPPORT 0
#define NBCI_FUNC_PLATCAPS 1
#define NBCI_FUNC_PLATPOLICY 4
#define NBCI_FUNC_DISPLAYSTATUS 5
#define NBCI_FUNC_GETOBJBYTYPE 16
#define NBCI_FUNC_GETALLOBJS 17
#define NBCI_FUNC_GETEVENTLIST 18
#define NBCI_FUNC_CALLBACKS 29
#define NBCI_FUNC_GETBACKLIGHT 20
#define NBCI_FUNC_GETLICENSE 22
#define NBCI_FUNC_GETEFITABLE 23
Scope (\_SB.PCI0.PEG0.DGPU)
{
Method (NBCI, 2, NotSerialized)
{
Printf("NBCI {")
Local0 = NVIDIA_ERROR_UNSUPPORTED
Switch (ToInteger(Arg0)) {
// Bit list of supported functions
Case (NBCI_FUNC_SUPPORT) {
// Supported functions: 0
Local0 = Buffer() {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
}
// Query Plaform Capabilities
Case (NBCI_FUNC_PLATCAPS) {
Printf(" NBCI_FUNC_PLATCAPS: Unimplemented!")
}
// Query Platform Policies
Case (NBCI_FUNC_PLATPOLICY) {
Printf(" NBCI_FUNC_PLATPOLICY: Unimplemented!")
}
// Query Display status
Case (NBCI_FUNC_DISPLAYSTATUS) {
Printf(" NBCI_FUNC_DISPLAYSTATUS: Unimplemented!")
}
// Fetch and specific Object by Type
Case (NBCI_FUNC_GETOBJBYTYPE) {
Printf(" NBCI_FUNC_GETOBJBYTYPE: Unimplemented!")
}
// Fetch all Objects
Case (NBCI_FUNC_GETALLOBJS) {
Printf(" NBCI_FUNC_GETALLOBJS: Unimplemented!")
}
// Get list of Notify events and their meaning
Case (NBCI_FUNC_GETEVENTLIST) {
Printf(" NBCI_FUNC_GETEVENTLIST: Unimplemented!")
}
// Get list of system-required callbacks
Case (NBCI_FUNC_CALLBACKS) {
Printf(" NBCI_FUNC_CALLBACKS: Unimplemented!")
}
// Get the Backlight setup settings
Case (NBCI_FUNC_GETBACKLIGHT) {
Printf(" NBCI_FUNC_GETBACKLIGHT: Unimplemented!")
}
// Get Software License Number
Case (NBCI_FUNC_GETLICENSE) {
Printf(" NBCI_FUNC_GETLICENSE: Unimplemented!")
}
// Get EFI System Table
Case (NBCI_FUNC_GETEFITABLE) {
Printf(" NBCI_FUNC_GETEFITABLE: Unimplemented!")
}
Default {
Printf(" Unsupported NBCI_FUNC: %o", ToInteger(Arg0))
Local0 = NVIDIA_ERROR_UNSUPPORTED
}
}
Printf("} NBCI")
Return(Local0)
}
}