From 0bf1dea8d82efff46847d3a6b0f5dac5667b40fe Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Tue, 13 Aug 2013 13:32:28 -0700 Subject: lynxpoint: Fix an issue clearing port change status bits The coreboot and ACPI code that clears USB3 PORTSC change status bits was not properly preserving the state of the PED (port enabled or disabled) status bit, and it could write 0 back to this field which would disable the port. Additionally add back the code that resets disconnected USB3 ports on the way into suspend (as stated in the BWG) but take care to clear the PME status bit so we don't immediately wake. suspend/resume with USB3 devices 1) suspend with no devices, plug in while suspended, then resume and verify that the devices are detected 2) suspend with USB3 devices inserted, then suspend and resume and verify that the devices are detected 3) suspend with USB3 devices inserted, then remove the devices while suspended, resume and ensure they can be detected again when inserted after resume Change-Id: Ic7e8d375dfe645cf0dc1f041c3a3d09d0ead1a51 Signed-off-by: Duncan Laurie Reviewed-on: https://gerrit.chromium.org/gerrit/65733 Reviewed-by: Aaron Durbin Commit-Queue: Aaron Durbin Reviewed-on: http://review.coreboot.org/4473 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi --- src/southbridge/intel/lynxpoint/acpi/usb.asl | 37 +++++++++++++++++++--------- src/southbridge/intel/lynxpoint/pch.h | 2 ++ src/southbridge/intel/lynxpoint/usb_xhci.c | 11 ++++++++- 3 files changed, 37 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/southbridge/intel/lynxpoint/acpi/usb.asl b/src/southbridge/intel/lynxpoint/acpi/usb.asl index c22dbb80bc..2fe67506b8 100644 --- a/src/southbridge/intel/lynxpoint/acpi/usb.asl +++ b/src/southbridge/intel/lynxpoint/acpi/usb.asl @@ -106,23 +106,36 @@ Device (XHCI) Field (XREG, DWordAcc, Lock, Preserve) { Offset (0x510), // PORTSCNUSB3[0] - , 17, - CLR1, 7, // Status Change bits 23:17 + PSC0, 32, Offset (0x520), // PORTSCNUSB3[1] - , 17, - CLR2, 7, // Status Change Bits 23:17 + PSC1, 32, Offset (0x530), // PORTSCNUSB3[2] - , 17, - CLR3, 7, // Status Change Bits 23:17 + PSC2, 32, Offset (0x540), // PORTSCNUSB3[3] - , 17, - CLR4, 7, // Status Change Bits 23:17 + PSC3, 32, } - Store (0x7f, CLR1) - Store (0x7f, CLR2) - Store (0x7f, CLR3) - Store (0x7f, CLR4) + // Port Enabled/Disabled (Bit 1) + Name (PEDB, ShiftLeft (1, 1)) + + // Change Status (Bits 23:17) + Name (CHST, ShiftLeft (0x7f, 17)) + + // Port 0 + And (PSC0, Not (PEDB), Local0) + Or (Local0, CHST, PSC0) + + // Port 1 + And (PSC1, Not (PEDB), Local0) + Or (Local0, CHST, PSC1) + + // Port 2 + And (PSC2, Not (PEDB), Local0) + Or (Local0, CHST, PSC2) + + // Port 3 + And (PSC3, Not (PEDB), Local0) + Or (Local0, CHST, PSC3) } Method (LPS0, 0, Serialized) diff --git a/src/southbridge/intel/lynxpoint/pch.h b/src/southbridge/intel/lynxpoint/pch.h index 6e1b10ca86..339636742b 100644 --- a/src/southbridge/intel/lynxpoint/pch.h +++ b/src/southbridge/intel/lynxpoint/pch.h @@ -366,6 +366,7 @@ int early_pch_init(const void *gpio_map, #define PWR_CTL_SET_D0 0x0 #define PWR_CTL_SET_D3 0x3 #define PWR_CTL_ENABLE_PME (1 << 8) +#define PWR_CTL_STATUS_PME (1 << 15) /* EHCI Memory Registers */ #define EHCI_USB_CMD 0x20 @@ -397,6 +398,7 @@ int early_pch_init(const void *gpio_map, #define XHCI_USB3_PORTSC_WOE (1 << 27) /* Wake on Overcurrent */ #define XHCI_USB3_PORTSC_WRC (1 << 19) /* Warm Reset Complete */ #define XHCI_USB3_PORTSC_LWS (1 << 16) /* Link Write Strobe */ +#define XHCI_USB3_PORTSC_PED (1 << 1) /* Port Enabled/Disabled */ #define XHCI_USB3_PORTSC_WPR (1 << 31) /* Warm Port Reset */ #define XHCI_USB3_PORTSC_PLS (0xf << 5) /* Port Link State */ #define XHCI_PLSR_DISABLED (4 << 5) /* Port is disabled */ diff --git a/src/southbridge/intel/lynxpoint/usb_xhci.c b/src/southbridge/intel/lynxpoint/usb_xhci.c index f866c4faba..500b57803a 100644 --- a/src/southbridge/intel/lynxpoint/usb_xhci.c +++ b/src/southbridge/intel/lynxpoint/usb_xhci.c @@ -61,7 +61,12 @@ static int usb_xhci_port_count_usb3(device_t dev) static void usb_xhci_reset_status_usb3(u32 mem_base, int port) { u32 portsc = mem_base + XHCI_USB3_PORTSC(port); - write32(portsc, read32(portsc) | XHCI_USB3_PORTSC_CHST); + u32 status = read32(portsc); + /* Do not set Port Enabled/Disabled field */ + status &= ~XHCI_USB3_PORTSC_PED; + /* Clear all change status bits */ + status |= XHCI_USB3_PORTSC_CHST; + write32(portsc, status); } static void usb_xhci_reset_port_usb3(u32 mem_base, int port) @@ -178,6 +183,9 @@ void usb_xhci_sleep_prepare(device_t dev, u8 slp_typ) reg32 &= ~((1 << 14) | (1 << 2)); write32(mem_base + 0x816c, reg32); + /* Reset disconnected USB3 ports */ + usb_xhci_reset_usb3(dev, 0); + /* Set MMIO 0x80e0[15] */ reg32 = read32(mem_base + 0x80e0); reg32 |= (1 << 15); @@ -186,6 +194,7 @@ void usb_xhci_sleep_prepare(device_t dev, u8 slp_typ) /* Set D3Hot state and enable PME */ pci_or_config16(dev, XHCI_PWR_CTL_STS, PWR_CTL_SET_D3); + pci_or_config16(dev, XHCI_PWR_CTL_STS, PWR_CTL_STATUS_PME); pci_or_config16(dev, XHCI_PWR_CTL_STS, PWR_CTL_ENABLE_PME); } -- cgit v1.2.3