soc/intel/tigerlake: Add Hot-Plug and PME event handlers for Thunderbolt

This change adds Hot-Plug and power management event handers(_L61 &
_L69) respectively for Thunderbolt in the GPE scope. The _L61 method
invokes sub-method HPEV to support Hot-Plug wake event from Thunderbolt
PCIe root ports. This method intercepts Presence Detect Changed
interrupt and make sure the L0s is disabled on empty slots. The _L69
method checks and clears root port's PME SCI status.

BUG=b:156435065
TEST=Verified multiple hot plug successfully with Lenovo dock.

Signed-off-by: John Zhao <john.zhao@intel.com>
Change-Id: I022cf4aa3f2ee459b9dc87849494e10755d995c8
Reviewed-on: https://review.coreboot.org/c/coreboot/+/42149
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
This commit is contained in:
John Zhao 2020-06-07 09:20:01 -07:00 committed by Duncan Laurie
parent a6e3b5ac09
commit f74aa649b1
1 changed files with 239 additions and 116 deletions

View File

@ -128,6 +128,127 @@ Scope (\_SB)
}
}
Scope (_GPE)
{
/* PCI Express Hot-Plug wake event */
Method (_L61, 0, NotSerialized)
{
/*
* Delay for 100ms to meet the timing requirements of the PCI Express Base
* Specification, Revision 1.0A, Section 6.6 ("...software must wait at least
* 100ms from the end of reset of one or more device before it is permitted
* to issue Configuration Requests to those devices").
*/
Sleep (100)
If (CondRefOf (\_SB.PCI0.TXHC)) {
/* Invoke PCIe root ports wake event handler */
\_SB.PCI0.TRP0.HPEV()
\_SB.PCI0.TRP1.HPEV()
\_SB.PCI0.TRP2.HPEV()
\_SB.PCI0.TRP3.HPEV()
}
/* Check Root Port 0 for a Hot Plug Event if the port is enabled */
If (((\_SB.PCI0.TRP0.VDID != 0xFFFFFFFF) && \_SB.PCI0.TRP0.HPSX)) {
If (\_SB.PCI0.TRP0.PDCX) {
/* Clear all status bits */
\_SB.PCI0.TRP0.PDCX = 1
\_SB.PCI0.TRP0.HPSX = 1
/*
* Intercept Presence Detect Changed interrupt and make sure
* the L0s is disabled on empty slots.
*/
If (!\_SB.PCI0.TRP0.PDSX) {
/*
* The PCIe slot is empty, so disable L0s on hot unplug.
*/
\_SB.PCI0.TRP0.L0SE = 0
}
/* Performs proper notification to the OS. */
Notify (\_SB.PCI0.TRP0, 0)
} Else {
/* False event. Clear Hot-Plug status, then exit. */
\_SB.PCI0.TRP0.HPSX = 1
}
}
/* Check Root Port 1 for a Hot Plug Event if the port is enabled */
If (((\_SB.PCI0.TRP1.VDID != 0xFFFFFFFF) && \_SB.PCI0.TRP1.HPSX)) {
If (\_SB.PCI0.TRP1.PDCX) {
\_SB.PCI0.TRP1.PDCX = 1
\_SB.PCI0.TRP1.HPSX = 1
If (!\_SB.PCI0.TRP1.PDSX) {
\_SB.PCI0.TRP1.L0SE = 0
}
Notify (\_SB.PCI0.TRP1, 0)
} Else {
\_SB.PCI0.TRP1.HPSX = 1
}
}
/* Check Root Port 2 for a Hot Plug Event if the port is enabled */
If (((\_SB.PCI0.TRP2.VDID != 0xFFFFFFFF) && \_SB.PCI0.TRP2.HPSX)) {
If (\_SB.PCI0.TRP2.PDCX) {
\_SB.PCI0.TRP2.PDCX = 1
\_SB.PCI0.TRP2.HPSX = 1
If (!\_SB.PCI0.TRP2.PDSX) {
\_SB.PCI0.TRP2.L0SE = 0
}
Notify (\_SB.PCI0.TRP2, 0)
} Else {
\_SB.PCI0.TRP2.HPSX = 1
}
}
/* Check Root Port 3 for a Hot Plug Event if the port is enabled */
If (((\_SB.PCI0.TRP3.VDID != 0xFFFFFFFF) && \_SB.PCI0.TRP3.HPSX)) {
If (\_SB.PCI0.TRP3.PDCX) {
\_SB.PCI0.TRP3.PDCX = 1
\_SB.PCI0.TRP3.HPSX = 1
If (!\_SB.PCI0.TRP3.PDSX) {
\_SB.PCI0.TRP3.L0SE = 0
}
Notify (\_SB.PCI0.TRP3, 0)
} Else {
\_SB.PCI0.TRP3.HPSX = 1
}
}
}
/* PCI Express power management event */
Method (_L69, 0, Serialized)
{
If (CondRefOf (\_SB.PCI0.TXHC)) {
If (\_SB.PCI0.TRP0.HPME() == 1) {
Notify (\_SB.PCI0.TDM0, 0x2)
Notify (\_SB.PCI0.TRP0, 0x2)
}
If (\_SB.PCI0.TRP1.HPME() == 1) {
Notify (\_SB.PCI0.TDM0, 0x2)
Notify (\_SB.PCI0.TRP1, 0x2)
}
If (\_SB.PCI0.TRP2.HPME() == 1) {
Notify (\_SB.PCI0.TDM1, 0x2)
Notify (\_SB.PCI0.TRP2, 0x2)
}
If (\_SB.PCI0.TRP3.HPME() == 1) {
Notify (\_SB.PCI0.TDM1, 0x2)
Notify (\_SB.PCI0.TRP3, 0x2)
}
}
/* Invoke PCIe root ports power management status handler */
\_SB.PCI0.TRP0.HPME()
\_SB.PCI0.TRP1.HPME()
\_SB.PCI0.TRP2.HPME()
\_SB.PCI0.TRP3.HPME()
}
}
Scope (\_SB.PCI0)
{
/*
@ -320,8 +441,7 @@ Scope (\_SB.PCI0)
{
If (\_SB.PCI0.TDM0.VDID == 0xFFFFFFFF) {
Printf("TDM0 does not exist.")
}
} Else {
If (\_SB.PCI0.TDM0.STAT == 0) {
/* DMA0 is in D3Cold early. */
\_SB.PCI0.TDM0.D3CX() /* RTD3 Exit */
@ -360,9 +480,11 @@ Scope (\_SB.PCI0)
} Else {
Printf("Drop TG0N due to it is already exit D3 cold.")
}
/* TBT RTD3 exit 10ms delay. */
Sleep (10)
}
}
/*
* TBT Group0 OFF method
@ -371,8 +493,7 @@ Scope (\_SB.PCI0)
{
If (\_SB.PCI0.TDM0.VDID == 0xFFFFFFFF) {
Printf("TDM0 does not exist.")
}
} Else {
If (\_SB.PCI0.TDM0.STAT == 1) {
/* DMA0 is not in D3Cold now. */
\_SB.PCI0.TDM0.D3CE() /* Enable DMA RTD3 */
@ -394,6 +515,7 @@ Scope (\_SB.PCI0)
}
}
}
}
/*
* TBT Group1 ON method
@ -402,8 +524,7 @@ Scope (\_SB.PCI0)
{
If (\_SB.PCI0.TDM1.VDID == 0xFFFFFFFF) {
Printf("TDM1 does not exist.")
}
} Else {
If (\_SB.PCI0.TDM1.STAT == 0) {
/* DMA1 is in D3Cold early. */
\_SB.PCI0.TDM1.D3CX() /* RTD3 Exit */
@ -442,9 +563,11 @@ Scope (\_SB.PCI0)
} Else {
Printf("Drop TG1N due to it is already exit D3 cold.")
}
/* TBT RTD3 exit 10ms delay. */
Sleep (10)
}
}
/*
* TBT Group1 OFF method
@ -453,8 +576,7 @@ Scope (\_SB.PCI0)
{
If (\_SB.PCI0.TDM1.VDID == 0xFFFFFFFF) {
Printf("TDM1 does not exist.")
}
} Else {
If (\_SB.PCI0.TDM1.STAT == 1) {
/* DMA1 is not in D3Cold now */
\_SB.PCI0.TDM1.D3CE() /* Enable DMA RTD3. */
@ -476,6 +598,7 @@ Scope (\_SB.PCI0)
}
}
}
}
PowerResource (TBT0, 5, 1)
{
@ -536,7 +659,7 @@ Scope (\_SB.PCI0)
}
If (Local0 == TCSS_IOM_ACK_TIMEOUT_IN_MS) {
Printf("Error: Error: Timeout occurred.")
Printf("Error: Timeout occurred.")
}
Else
{