lynxpoint xhci: Add ACPI D0/D3 workarounds

There are specific programming requirements for the usb3 ports
on all LynxPoint chipsets when transitioning to D0 or D3.

LynxPoint-LP has additional workaround steps needed involving
resetting the disconnected ports when transitioning to D0.

The workarounds are implemented in ACPI code so the controller
can transition properly into D3 at runtime.

Change-Id: I3b428562f48c9cb250b97779a3b2753ed4f81509
Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/62632
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/4374
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <patrick@georgi-clan.de>
This commit is contained in:
Duncan Laurie 2013-07-19 08:41:38 -07:00 committed by Patrick Georgi
parent af98062817
commit 80fd5c4461
1 changed files with 291 additions and 1 deletions

View File

@ -70,6 +70,296 @@ Device (XHCI)
{ {
Name (_ADR, 0x00140000) Name (_ADR, 0x00140000)
Name (PLSD, 5) // Port Link State - RxDetect
Name (PLSP, 7) // Port Link State - Polling
OperationRegion (XPRT, PCI_Config, 0x00, 0x100)
Field (XPRT, AnyAcc, NoLock, Preserve)
{
Offset (0x0),
DVID, 16,
Offset (0x10),
, 16,
XMEM, 16, // MEM_BASE
Offset (0x74),
D0D3, 2,
, 6,
PMEE, 1, // PME_EN
, 6,
PMES, 1, // PME_STS
Offset (0xb0),
, 13,
MB13, 1,
MB14, 1,
Offset (0xd0),
PR2R, 32, // USB2PR
PR2M, 32, // USB2PRM
PR3R, 32, // USB3PR
PR3M, 32, // USB3PRM
}
// Clear status bits
Method (LPCL, 0, Serialized)
{
OperationRegion (XREG, SystemMemory,
ShiftLeft (^XMEM, 16), 0x600)
Field (XREG, DWordAcc, Lock, Preserve)
{
Offset (0x510), // PORTSCNUSB3[0]
, 17,
CLR1, 7, // Status Change bits 23:17
Offset (0x520), // PORTSCNUSB3[1]
, 17,
CLR2, 7, // Status Change Bits 23:17
Offset (0x530), // PORTSCNUSB3[2]
, 17,
CLR3, 7, // Status Change Bits 23:17
Offset (0x540), // PORTSCNUSB3[3]
, 17,
CLR4, 7, // Status Change Bits 23:17
}
Store (0x7f, CLR1)
Store (0x7f, CLR2)
Store (0x7f, CLR3)
Store (0x7f, CLR4)
}
Method (LPS0, 0, Serialized)
{
OperationRegion (XREG, SystemMemory,
ShiftLeft (^XMEM, 16), 0x600)
Field (XREG, DWordAcc, Lock, Preserve)
{
Offset (0x510), // PORTSCNUSB3
, 5,
PLS1, 4, // [8:5] Port Link State
PPR1, 1, // [9] Port Power
, 7,
CSC1, 1, // [17] Connect Status Change
, 1,
WRC1, 1, // [19] Warm Port Reset Change
, 11,
WPR1, 1, // [31] Warm Port Reset
Offset (0x520), // PORTSCNUSB3
, 5,
PLS2, 4, // [8:5] Port Link State
PPR2, 1, // [9] Port Power
, 7,
CSC2, 1, // [17] Connect Status Change
, 1,
WRC2, 1, // [19] Warm Port Reset Change
, 11,
WPR2, 1, // [31] Warm Port Reset
Offset (0x530), // PORTSCNUSB3
, 5,
PLS3, 4, // [8:5] Port Link State
PPR3, 1, // [9] Port Power
, 7,
CSC3, 1, // [17] Connect Status Change
, 1,
WRC3, 1, // [19] Warm Port Reset Change
, 11,
WPR3, 1, // [31] Warm Port Reset
Offset (0x540), // PORTSCNUSB3
, 5,
PLS4, 4, // [8:5] Port Link State
PPR4, 1, // [9] Port Power
, 7,
CSC4, 1, // [17] Connect Status Change
, 1,
WRC4, 1, // [19] Warm Port Reset Change
, 11,
WPR4, 1, // [31] Warm Port Reset
}
// Wait for all powered ports to finish polling
Store (10, Local0)
While (LOr (LOr (LAnd (LEqual (PPR1, 1), LEqual (PLS1, PLSP)),
LAnd (LEqual (PPR2, 1), LEqual (PLS2, PLSP))),
LOr (LAnd (LEqual (PPR3, 1), LEqual (PLS3, PLSP)),
LAnd (LEqual (PPR4, 1), LEqual (PLS4, PLSP)))))
{
If (LEqual (Local0, 0)) {
Break
}
Decrement (Local0)
Stall (10)
}
// For each USB3 Port:
// If port is disconnected (PLS=5 PP=1 CSC=0)
// 1) Issue warm reset (WPR=1)
// 2) Poll for warm reset complete (WRC=0)
// 3) Write 1 to port status to clear
// Local# indicate if port is reset
Store (0, Local1)
Store (0, Local2)
Store (0, Local3)
Store (0, Local4)
If (LAnd (LEqual (PLS1, PLSD),
LAnd (LEqual (CSC1, 0), LEqual (PPR1, 1)))) {
Store (1, WPR1) // Issue warm reset
Store (1, Local1)
}
If (LAnd (LEqual (PLS2, PLSD),
LAnd (LEqual (CSC2, 0), LEqual (PPR2, 1)))) {
Store (1, WPR2) // Issue warm reset
Store (1, Local2)
}
If (LAnd (LEqual (PLS3, PLSD),
LAnd (LEqual (CSC3, 0), LEqual (PPR3, 1)))) {
Store (1, WPR3) // Issue warm reset
Store (1, Local3)
}
If (LAnd (LEqual (PLS4, PLSD),
LAnd (LEqual (CSC4, 0), LEqual (PPR4, 1)))) {
Store (1, WPR4) // Issue warm reset
Store (1, Local4)
}
// Poll for warm reset complete on all ports that were reset
Store (10, Local0)
While (LOr (LOr (LAnd (LEqual (Local1, 1), LEqual (WRC1, 0)),
LAnd (LEqual (Local2, 1), LEqual (WRC2, 0))),
LOr (LAnd (LEqual (Local3, 1), LEqual (WRC3, 0)),
LAnd (LEqual (Local4, 1), LEqual (WRC4, 0)))))
{
If (LEqual (Local0, 0)) {
Break
}
Decrement (Local0)
Stall (10)
}
// Clear status bits in all ports
LPCL ()
}
Method (_PS0, 0, Serialized)
{
If (LEqual (^DVID, 0xFFFF)) {
Return ()
}
If (LOr (LEqual (^XMEM, 0xFFFF), LEqual (^XMEM, 0x0000))) {
Return ()
}
OperationRegion (XREG, SystemMemory,
Add (ShiftLeft (^XMEM, 16), 0x8000), 0x200)
Field (XREG, DWordAcc, Lock, Preserve)
{
Offset (0x0e0), // AUX Reset Control 1
, 15,
AX15, 1,
Offset (0x154), // AUX Domain PM Control Register 2
, 31,
CLK2, 1,
Offset (0x16c), // AUX Clock Control
, 2,
CLK0, 1,
, 11,
CLK1, 1, // USB3 Port Aux/Core Clock Gating Enable
}
// If device is in D3, set back to D0
Store (^D0D3, Local0)
if (LEqual (Local0, 3)) {
Store (0, ^D0D3)
}
If (\ISLP ()) {
// Clear PCI 0xB0[14:13]
Store (0, ^MB13)
Store (0, ^MB14)
// Clear MMIO 0x816C[14,2]
Store (0, CLK0)
Store (0, CLK1)
}
// Set MMIO 0x8154[31]
Store (1, CLK2)
If (\ISLP ()) {
// Handle per-port reset if needed
LPS0 ()
// Set MMIO 0x80e0[15]
Store (1, AX15)
}
// Put device in D3 if it was there originally
If (LEqual (Local0, 3)) {
Store (3, ^D0D3)
}
Return ()
}
Method (_PS3, 0, Serialized)
{
If (LEqual (^DVID, 0xFFFF)) {
Return ()
}
If (LOr (LEqual (^XMEM, 0xFFFF), LEqual (^XMEM, 0x0000))) {
Return ()
}
OperationRegion (XREG, SystemMemory,
Add (ShiftLeft (^XMEM, 16), 0x8000), 0x200)
Field (XREG, DWordAcc, Lock, Preserve)
{
Offset (0x0e0), // AUX Reset Control 1
, 15,
AX15, 1,
Offset (0x154), // AUX Domain PM Control Register 2
, 31,
CLK2, 1,
Offset (0x16c), // AUX Clock Control
, 2,
CLK0, 1,
, 11,
CLK1, 1, // USB3 Port Aux/Core Clock Gating Enable
}
Store (1, ^PMES) // Clear PME Status
Store (1, ^PMEE) // Enable PME
// If device is in D3, set back to D0
Store (^D0D3, Local0)
if (LEqual (Local0, 3)) {
Store (0, ^D0D3)
}
If (\ISLP ()) {
// Set PCI 0xB0[14:13]
Store (1, ^MB13)
Store (1, ^MB14)
// Set MMIO 0x816C[14,2]
Store (1, CLK0)
Store (1, CLK1)
}
// Clear MMIO 0x8154[31]
Store (0, CLK2)
If (\ISLP ()) {
// Clear MMIO 0x80e0[15]
Store (0, AX15)
}
// Put device in D3
If (LEqual (Local0, 3)) {
Store (3, ^D0D3)
}
Return ()
}
Name (PRWH, Package(){ 0x0d, 3 }) // LPT-H Name (PRWH, Package(){ 0x0d, 3 }) // LPT-H
Name (PRWL, Package(){ 0x6d, 3 }) // LPT-LP Name (PRWL, Package(){ 0x6d, 3 }) // LPT-LP