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 <dlaurie@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/65733
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Commit-Queue: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/4473
Tested-by: build bot (Jenkins)
Reviewed-by: Patrick Georgi <patrick@georgi-clan.de>
diff --git a/src/southbridge/intel/lynxpoint/usb_xhci.c b/src/southbridge/intel/lynxpoint/usb_xhci.c
index f866c4f..500b578 100644
--- a/src/southbridge/intel/lynxpoint/usb_xhci.c
+++ b/src/southbridge/intel/lynxpoint/usb_xhci.c
@@ -61,7 +61,12 @@
 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 @@
 		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 @@
 
 	/* 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);
 }