mb/google/brya: Add PEG and initial Nvidia dGPU ASL support

Some brya variants will use a GN20 series Nvidia GPU, which requires
quite a bit of ACPI support code to be written for it. This patch
lands a decent bit of the initial code for it on the brya platform,
including:

1) PEG RTD3 methods
2) DGPU power operations (RTD3 and GCOFF, NVJT _DSM and other Methods)
3) NVOP _DSM method

There will be more support to come later, this is all written to
specifications from the Nvidia Software Design Guide for GN20.

BUG=b:214581763
TEST=build patch train

Signed-off-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Change-Id: Ifce1610210e9636e87dda4b55c8287334adfcc42
Reviewed-on: https://review.coreboot.org/c/coreboot/+/62931
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Eric Lai <eric_lai@quanta.corp-partner.google.com>
Reviewed-by: Subrata Banik <subratabanik@google.com>
This commit is contained in:
Tim Wawrzynczak 2022-02-25 09:13:49 -07:00
parent 2efd8315f2
commit c852533379
9 changed files with 719 additions and 0 deletions

View File

@ -264,4 +264,9 @@ config MEMORY_SOLDERDOWN
config HAVE_SLP_S0_GATE
def_bool n
config INCLUDE_NVIDIA_GPU_ASL
def_bool n
help
Select this if the variant has an Nvidia GN20 GPU attached to PEG1
endif # BOARD_GOOGLE_BRYA_COMMON

View File

@ -0,0 +1,44 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#define NV_ERROR_SUCCESS 0x0
#define NV_ERROR_UNSPECIFIED 0x80000001
#define NV_ERROR_UNSUPPORTED 0x80000002
#define PCI_OWNER_SBIOS 0x0
#define PCI_OWNER_DRIVER 0x1
#define OPTIMUS_POWER_CONTROL_DISABLE 0x2
#define OPTIMUS_POWER_CONTROL_ENABLE 0x3
#define OPTIMUS_CONTROL_NO_RUN_PS0 0x0
#define OPTIMUS_CONTROL_RUN_PS0 0x1
#define GC6_STATE_EXITED 0x0
#define GC6_STATE_ENTERED 0x1
#define GC6_STATE_TRANSITION 0x2
#define GC6_DEFER_DISABLE 0x0
#define GC6_DEFER_ENABLE 0x1
#define NOTIFY_GPS_EVENT_STATUS_CHANGE 0xc0
#define NOTIFY_GPS_NVPCF_STATUS_CHANGE 0xc5
#define NOTIFY_GPS_EVENT_LIMIT_POWER_0 0xd1
#define NOTIFY_GPS_EVENT_LIMIT_POWER_1 0xd2
#define NOTIFY_GPS_EVENT_LIMIT_POWER_2 0xd3
#define NOTIFY_GPS_EVENT_LIMIT_POWER_3 0xd4
#define NOTIFY_GPS_EVENT_LIMIT_POWER_4 0xd5
/* Defines for NVJT subfunction */
#define NVJT_GPC_GSS 0
#define NVJT_GPC_EGNS 1
#define NVJT_GPC_EGIS 2
#define NVJT_GPS_XGXS 3
#define NVJT_GPS_XGIS 4
#define UUID_NVOP "a486d8f8-0bda-471b-a72b-6042a6b5bee0"
#define UUID_NVJT "cbeca351-067b-4924-9cbd-b46b00b86f34"
#define UUID_NBCI "d4a50b75-65c7-46f7-bfb7-41514cea0244"
#define REVISION_MIN_NVOP 0x100
#define REVISION_MIN_NVJT 0x100
#define REVISION_MIN_NBCI 0x102

View File

@ -0,0 +1,46 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_defines.h"
Scope (\_SB.PCI0.PEG0)
{
#include "peg.asl"
Device (PEGP)
{
Name (_ADR, 0x0)
OperationRegion (PCIC, PCI_Config, 0x00, 0x100)
Field (PCIC, DWordAcc, NoLock, Preserve)
{
NVID, 16,
NDID, 16,
CMDR, 8,
VGAR, 2008, /* VGA Registers */
}
#include "utility.asl"
#include "power.asl"
#include "nvop.asl"
#include "nvjt.asl"
Method (_DSM, 4, Serialized)
{
If (Arg0 == ToUUID (UUID_NVOP))
{
If (ToInteger(Arg1) >= REVISION_MIN_NVOP)
{
Return (NVOP (Arg2, Arg3))
}
}
ElseIf (Arg0 == ToUUID (UUID_NVJT))
{
If (ToInteger (Arg1) >= REVISION_MIN_NVJT)
{
Return (NVJT (Arg2, Arg3))
}
}
Return (NV_ERROR_UNSUPPORTED)
}
}
}

View File

@ -0,0 +1,129 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#define JT_FUNC_SUPPORT 0
#define JT_FUNC_CAPS 1
#define JT_FUNC_POWERCONTROL 2
#define JT_FUNC_PLATPOLICY 3
Method (NVJT, 2, Serialized)
{
Switch (ToInteger(Arg0))
{
Case (JT_FUNC_SUPPORT)
{
Return (ITOB(
(1 << JT_FUNC_SUPPORT) |
(1 << JT_FUNC_CAPS) |
(1 << JT_FUNC_POWERCONTROL) |
(1 << JT_FUNC_PLATPOLICY)))
}
Case (JT_FUNC_CAPS)
{
Return (ITOB(
(0 << 0) | /* JTE: G-Sync NVSR Power Features Enabled */
(1 << 0) | /* NVSE: NVSR Disabled */
(0 << 3) | /* PPR: Panel Power Rail */
(0 << 5) | /* SRPR: Self-Refresh Controller Power Rail */
(0 << 6) | /* FBPR: FB Power Rail */
(0 << 8) | /* GPR: GPU Power Rail */
(0 << 10) | /* GCR: GC6 ROM */
(1 << 11) | /* PTH: No SMI Handler */
(0 << 12) | /* NOT: Supports Notify on GC6 State done */
(1 << 13) | /* MHYB: MS Hybrid Support (deferred GC6) */
(0 << 14) | /* RPC: Root Port Control */
(0 << 15) | /* GC6 Version (GC6-E) */
(0 << 17) | /* GEI: GC6 Exit ISR Support */
(0 << 18) | /* GSW: GC6 Self Wakeup */
(0x200 << 20))) /* MXRV: Highest Revision */
}
Case (JT_FUNC_POWERCONTROL)
{
CreateField (Arg1, 0, 3, GPC) /* GPU Power Control */
CreateField (Arg1, 4, 1, PPC) /* Panel Power Control */
CreateField (Arg1, 14, 2, DFGC) /* Defer GC6 enter/exit */
CreateField (Arg1, 16, 3, GPCX) /* Deferred GC6 exit */
/* Deferred GC6 entry/exit is requested */
If (ToInteger(GPC) != 0 || ToInteger(DFGC) != 0)
{
DFEN = ToInteger(DFGC)
DFCI = ToInteger(GPC)
DFCO = ToInteger(GPCX)
}
Local0 = Buffer (4) { 0x0 }
CreateField (Local0, 0, 3, CGCS) /* Current GC State */
CreateField (Local0, 3, 1, CGPS) /* Current GPU power status */
CreateField (Local0, 7, 1, CPSS) /* Current panel and SRC state */
/* Leave early if deferred GC6 is requested */
If (DFEN != 0)
{
CGCS = 1
CGPS = 1
Return (Local0)
}
Switch (ToInteger(GPC))
{
/* Get GCU GCx Sleep Status */
Case (NVJT_GPC_GSS)
{
If (^_STA () != 0)
{
CGPS = 1
CGCS = 1
}
Else
{
CGPS = 0
CGCS = 3
}
}
Case (NVJT_GPC_EGNS)
{
/* Enter GC6; no self-refresh */
GC6I ()
CPSS = 1
CGCS = 0
}
Case (NVJT_GPC_EGIS)
{
/* Enter GC6; enable self-refresh */
GC6I ()
If (ToInteger (PPC) == 0)
{
CPSS = 0
}
CGCS = 0
}
Case (NVJT_GPS_XGXS)
{
/* Exit GC6; stop self-refresh */
GC6O ()
CGCS = 1
CGPS = 1
If (ToInteger (PPC) != 0)
{
CPSS = 0
}
}
Case (NVJT_GPS_XGIS)
{
/* Exit GC6 for self-refresh */
GC6O ()
CGCS = 1
CGPS = 1
If (ToInteger (PPC) != 0)
{
CPSS = 0
}
}
}
Return (Local0)
}
}
Return (NV_ERROR_UNSUPPORTED)
}

View File

@ -0,0 +1,69 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#define NVOP_FUNC_SUPPORT 0x00
#define NVOP_FUNC_GET_OBJ_BY_TYPE 0x10
#define NVOP_FUNC_OPTIMUS_CAPS 0x1a
#define NVOP_FUNC_OPTIMUS_STATUS 0x1b
Method (NVOP, 2, Serialized)
{
Switch (ToInteger (Arg0))
{
Case (NVOP_FUNC_SUPPORT)
{
Return (ITOB (
(1 << NVOP_FUNC_SUPPORT) |
(1 << NVOP_FUNC_OPTIMUS_CAPS) |
(1 << NVOP_FUNC_OPTIMUS_STATUS)))
}
Case (NVOP_FUNC_OPTIMUS_CAPS)
{
CreateField(Arg1, 0, 1, FLUP) /* Flag Update */
CreateField(Arg1, 1, 1, CSOT) /* Change configuration Space Owner Target */
CreateField(Arg1, 2, 1, CSOW) /* Change configuration Space Owner Write */
CreateField(Arg1, 24, 2, NPCE) /* New Power Control Enable setting */
/* Change Optimus power control capabilities */
If (ToInteger (FLUP) != 0 && ToInteger (NPCE) != 0)
{
OPCS = NPCE
}
/* Change PCI configuration space save/restore owner */
If (ToInteger (CSOW) == 1)
{
PCIO = CSOT
}
/* Current GPU Control Status */
If (\_SB.PCI0.PEG0.PGPR._STA == 1)
{
Local0 = 3
}
Else
{
Local0 = 0
}
Return (ITOB (
(1 << 0) | /* Optimus Enabled */
(Local0 << 3) | /* Current GPU Control Status */
(0 << 6) | /* Shared Discrete GPU Hotplug Capabilities */
(0 << 7) | /* MUXed DDC/Aux Capabilities */
(PCIO << 8) | /* PCIe Configuration Space Owner */
(1 << 24) | /* Platform Optimus Power Capabilities */
(0 << 27))) /* Optimus HD Audio Codec Capabilities */
}
Case (NVOP_FUNC_OPTIMUS_STATUS)
{
Return (ITOB (
(0 << 0) | /* Optimus Audio Codec Control */
(0 << 2) | /* Request GPU Power State */
(0 << 4) | /* Evaluate Requested GPU Power State */
(0 << 5) | /* Request Optimus Adapter Policy */
(0 << 7))) /* Evaluate Requested Optimus Adapter Selection */
}
}
Return (NV_ERROR_UNSUPPORTED)
}

View File

@ -0,0 +1,95 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
External (\_SB.PCI0.DGPU, DeviceObj)
External (\_SB.PCI0.PEG0.PEGP._OFF, MethodObj)
External (\_SB.PCI0.PEG0.PEGP._ON, MethodObj)
OperationRegion (PCIC, PCI_Config, 0x00, 0x100)
Field (PCIC, AnyAcc, NoLock, Preserve)
{
Offset (0x52),
, 13,
LASX, 1, /* Link Active Status */
Offset (0xe0),
, 7,
NCB7, 1, /* Scratch bit to save L2/3 state */
Offset (0xe2),
, 2,
L23E, 1, /* L23_Rdy Entry request */
L23R, 1 /* L23_Rdy Detect Transition */
}
/* L2/3 Entry sequence */
Method (DL23, 0, Serialized)
{
L23E = 1
Local0 = 8
While (Local0 > 0)
{
If (!L23E)
{
Break
}
Sleep (16)
Local0--
}
NCB7 = 1
}
/* L2/3 exit seqeuence */
Method (LD23, 0, Serialized)
{
If (!NCB7)
{
Return
}
L23R = 1
Local0 = 20
While (Local0 > 0)
{
If (!L23R)
{
Break
}
Sleep (16)
Local0--
}
NCB7 = 0
Local0 = 8
While (Local0 > 0)
{
If (LASX == 1)
{
Break
}
Sleep (16)
Local0--
}
}
/* PEG Power Resource */
PowerResource (PGPR, 0, 0)
{
Method (_ON, 0, Serialized)
{
/* Power up GPU from GCOFF (or GC6 exit if deferred) */
\_SB.PCI0.PEG0.PEGP._ON ()
_STA = 1
}
Method (_OFF, 0, Serialized)
{
/* Power down GPU to GCOFF (or GC6 entry if deferred) */
_STA = 0
\_SB.PCI0.PEG0.PEGP._OFF ()
}
Name (_STA, 0)
}
Name (_PR0, Package() { PGPR })
Name (_PR2, Package() { PGPR })
Name (_PR3, Package() { PGPR })

View File

@ -0,0 +1,297 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* 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_NVVDD_PG GPP_E16
#define GPIO_PEXVDD_PWR_EN GPP_E10
#define GPIO_PEXVDD_PG GPP_E17
#define GPIO_FBVDD_PWR_EN GPP_A17
#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_A19
#define GC6_DEFER_TYPE_EXIT_GC6 3
/* Optimus Power Control State */
Name (OPCS, OPTIMUS_POWER_CONTROL_DISABLE)
/* PCI configuration space Owner */
Name (PCIO, PCI_OWNER_SBIOS)
/* 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)
/* 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)
/* "GC6 In", i.e. GC6 Entry Sequence */
Method (GC6I, 0, Serialized)
{
GC6E = GC6_STATE_TRANSITION
/* Put PCIe link into L2/3 */
\_SB.PCI0.PEG0.DL23 ()
/* Assert GPU_PERST_L */
\_SB.PCI0.STXS (GPIO_GPU_PERST_L)
/* Deassert PG_GPU_ALLRAILS */
\_SB.PCI0.CTXS (GPIO_GPU_ALLRAILS_PG)
/* Deassert EN_PP0950_GPU_X */
\_SB.PCI0.CTXS (GPIO_PEXVDD_PWR_EN)
/* Wait for de-assertion of PG_PP0950_GPU */
GPPL (GPIO_PEXVDD_PG, 0, 20)
/* Deassert EN_PPVAR_GPU_NVVDD */
\_SB.PCI0.CTXS (GPIO_NVVDD_PWR_EN)
/* Wait for de-assertion of PG_PPVAR_GPU_NVVDD */
GPPL (GPIO_NVVDD_PG, 0, 20)
/* Deassert EN_PCH_PPVAR_GPU_FBVDDQ */
\_SB.PCI0.CTXS (GPIO_FBVDD_PWR_EN)
/* Deassert EN_PP3300_GPU */
\_SB.PCI0.CTXS (GPIO_NV33_PWR_EN)
/* Wait for de-assertion of PG_PP3300_GPU */
GPPL (GPIO_NV33_PG, 0, 20)
GC6E = GC6_STATE_ENTERED
}
/* "GC6 Out", i.e. GC6 Exit Sequence */
Method (GC6O, 0, Serialized)
{
GC6E = GC6_STATE_TRANSITION
/* Assert EN_PP3300_GPU */
\_SB.PCI0.STXS (GPIO_NV33_PWR_EN)
/* Wait for assertion of PG_PP3300_GPU */
GPPL (GPIO_NV33_PG, 1, 20)
/* Deassert GPU_PERST_L */
\_SB.PCI0.CTXS (GPIO_GPU_PERST_L)
/* Put PCIe link into L0 state */
\_SB.PCI0.PEG0.LD23 ()
/* Wait for GPU to assert GPU_NVVDD_EN */
GPPL (GPIO_GPU_NVVDD_EN, 1, 20)
/*
* There is a 4ms window once the GPU asserts GPU_NVVDD_EN to
* perform the following:
* 1. Enable GPU_NVVDD
* 2. Enable GPU_PEX
* 3. Wait for all PG
* 4. Assert FBVDD
* At the end of the 4ms window, the GPU will deassert its
* GPIO1_GC6_FB_EN signal that is used to keep the FBVDD
* rail up during GC6.
*/
\_SB.PCI0.STXS (GPIO_NVVDD_PWR_EN)
Stall (20)
\_SB.PCI0.STXS (GPIO_PEXVDD_PWR_EN)
GPPL (GPIO_NVVDD_PG, 1, 4)
GPPL (GPIO_PEXVDD_PG, 1, 4)
\_SB.PCI0.STXS (GPIO_FBVDD_PWR_EN)
/* Assert PG_GPU_ALLRAILS */
\_SB.PCI0.STXS (GPIO_GPU_ALLRAILS_PG)
GC6E = GC6_STATE_EXITED
}
/* GCOFF exit sequence */
Method (PGON, 0, Serialized)
{
/* Assert PERST# */
\_SB.PCI0.CTXS (GPIO_GPU_PERST_L)
/* Ramp up 1.8V rail */
\_SB.PCI0.STXS (GPIO_1V8_PWR_EN)
GPPL (GPIO_1V8_PG, 1, 20)
/* Ramp up NV33 rail */
\_SB.PCI0.STXS (GPIO_NV33_PWR_EN)
GPPL (GPIO_NV33_PG, 1, 20)
/* Ramp up NVVDD rail */
\_SB.PCI0.STXS (GPIO_NVVDD_PWR_EN)
GPPL (GPIO_NVVDD_PG, 1, 5)
/* Ramp up PEXVDD rail */
\_SB.PCI0.STXS (GPIO_PEXVDD_PWR_EN)
GPPL (GPIO_PEXVDD_PG, 1, 5)
/* Ramp up FBVDD rail */
\_SB.PCI0.STXS (GPIO_FBVDD_PWR_EN)
GPPL (GPIO_FBVDD_PG, 1, 5)
/* All rails are good */
\_SB.PCI0.STXS (GPIO_GPU_ALLRAILS_PG)
Sleep (1)
/* Deassert PERST# */
\_SB.PCI0.STXS (GPIO_GPU_PERST_L)
}
/* GCOFF entry sequence */
Method (PGOF, 0, Serialized)
{
/* Assert PERST# */
\_SB.PCI0.CTXS (GPIO_GPU_PERST_L)
Sleep (5)
/* All rails are about to go down */
\_SB.PCI0.CTXS (GPIO_GPU_ALLRAILS_PG)
/* Ramp down FBVDD */
\_SB.PCI0.CTXS (GPIO_FBVDD_PWR_EN)
GPPL (GPIO_FBVDD_PG, 0, 20)
/* Ramp down PEXVDD */
\_SB.PCI0.CTXS (GPIO_PEXVDD_PWR_EN)
GPPL (GPIO_PEXVDD_PG, 0, 20)
/* Ramp down NVVDD */
\_SB.PCI0.CTXS (GPIO_NVVDD_PWR_EN)
GPPL (GPIO_NVVDD_PG, 0, 20)
/* Ramp down NV33 */
\_SB.PCI0.CTXS (GPIO_NV33_PWR_EN)
GPPL (GPIO_NV33_PG, 0, 20)
/* Ramp down 1.8V */
\_SB.PCI0.CTXS (GPIO_1V8_PWR_EN)
GPPL (GPIO_1V8_PG, 0, 20)
}
/* Handle deferred GC6 vs. poweron request */
Method (NPON, 0, Serialized)
{
If (DFEN == GC6_DEFER_ENABLE) /* 1 */
{
If (DFCO == GC6_DEFER_TYPE_EXIT_GC6) /* 3 */
{
GC6O ()
}
DFEN = GC6_DEFER_DISABLE
}
Else
{
PGON ()
}
}
/* 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
{
PGOF ()
}
}
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 _OFF, _PS0 must run _ON */
OPS0 = OPTIMUS_CONTROL_RUN_PS0
/* OPCS is one-shot, so reset it */
OPCS = OPTIMUS_POWER_CONTROL_DISABLE
}
}
/*
* Normally, _ON and _OFF of the power resources listed in _PRx will be
* evaluated before entering D0/D3. However, for Optimus, the package
* should refer to the PCIe controller itself, not a dependent device.
*/
Name (_PR0, Package() { \_SB.PCI0.PEG0 })
Name (_PR3, Package() { \_SB.PCI0.PEG0 })
Method (_STA, 0, Serialized)
{
If (GC6E == GC6_STATE_EXITED &&
\_SB.PCI0.GTXS(GPIO_GPU_ALLRAILS_PG) == 1)
{
Return (0xF)
}
Else
{
Return (0)
}
}

View File

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Poll a GPIO until it goes to the specified state
* Arg0 == GPIO #
* Arg1 == state (0 or 1)
* Arg2 == timeout in ms
*/
Method (GPPL, 3, Serialized)
{
Local0 = GRXS (Arg0)
Local7 = Arg2 * 10000
Local7 = Timer + Local7
While (Local0 != Arg1 && Timer < Local7)
{
Stall (10)
Local0 = \_SB.PCI0.GRXS (Arg0)
}
}
/* Convert from 32-bit integer to 4-byte buffer (little-endian) */
Method (ITOB, 1)
{
Local0 = Buffer(4) { 0, 0, 0, 0 }
Local0[0] = Arg0 & 0xFF
Local0[1] = (Arg0 >> 8) & 0xFF
Local0[2] = (Arg0 >> 16) & 0xFF
Local0[3] = (Arg0 >> 24) & 0xFF
Return (Local0)
}

View File

@ -44,4 +44,8 @@ DefinitionBlock(
/* ACPI code for EC functions */
#include <ec/google/chromeec/acpi/ec.asl>
}
#if CONFIG(INCLUDE_NVIDIA_GPU_ASL)
#include "acpi/gpu_top.asl"
#endif
}