Paul Menzel (paulepanter@users.sourceforge.net) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/6016
-gerrit
commit 42d37442ef5bb51be20e52728566a61636373de6 Author: Duncan Laurie dlaurie@chromium.org Date: Wed Sep 25 14:08:16 2013 -0700
intel/lynxpoint: xhci: Add more suspend/resume changes
I have been attempting to work around USB3 issues that appear in the kernel with hacks in the firmware, but this is resulting in more headaches in the kernel.
Instead remove all the work that was being done at resume time and undo the change that was issuing a warm reset to all ports at suspend time.
The bad device behavior will be dealt with at the kernel level to handle devices that get stuck in polling state after enable/disable sequence.
BUG=chrome-os-partner:22754 BRANCH=falco,peppy,wolf,leon TEST=manual:
suspend/resume with several misbehaving devices: Kingston USB3 Media Reader Transcend USB3 Media Reader Various ADATA USB3 drives Various Kingston USB3 sticks
Original-Change-Id: I0894454af42d2ced456fe0da921d74c9e74902d0 Signed-off-by: Duncan Laurie dlaurie@chromium.org Reviewed-on: https://chromium-review.googlesource.com/170107 Reviewed-by: Aaron Durbin adurbin@chromium.org (cherry picked from commit c2abb4d0dad6ed00e1e230d604c4c0a76eb4eef7)
Change-Id: Ib215d9c230f90a1c9f34bf29254bb9feec28c67e Signed-off-by: Duncan Laurie dlaurie@chromium.org Reviewed-on: https://chromium-review.googlesource.com/170578 [pm: rebase to master branch of coreboot upstream] Signed-off-by: Paul Menzel paulepanter@users.sourceforge.net --- src/southbridge/intel/lynxpoint/usb_xhci.c | 90 +++--------------------------- 1 file changed, 9 insertions(+), 81 deletions(-)
diff --git a/src/southbridge/intel/lynxpoint/usb_xhci.c b/src/southbridge/intel/lynxpoint/usb_xhci.c index f6409b4..09bde94 100644 --- a/src/southbridge/intel/lynxpoint/usb_xhci.c +++ b/src/southbridge/intel/lynxpoint/usb_xhci.c @@ -37,6 +37,8 @@ static u32 usb_xhci_mem_base(device_t dev) return mem_base & ~0xf; }
+#ifdef __SMM__ + static int usb_xhci_port_count_usb3(device_t dev) { if (pch_is_lp()) { @@ -78,8 +80,6 @@ static void usb_xhci_reset_port_usb3(u32 mem_base, int port) #define XHCI_RESET_DELAY_US 1000 /* 1ms */ #define XHCI_RESET_TIMEOUT 100 /* 100ms */
-#ifdef __SMM__ - /* * 1) Wait until port is done polling * 2) If port is disconnected @@ -87,7 +87,7 @@ static void usb_xhci_reset_port_usb3(u32 mem_base, int port) * b) Poll for warm reset complete * c) Write 1 to port change status bits */ -static void usb_xhci_reset_usb3(device_t dev) +static void usb_xhci_reset_usb3(device_t dev, int all) { u32 status, port_disabled; int timeout, port; @@ -127,7 +127,10 @@ static void usb_xhci_reset_usb3(device_t dev) continue; status = read32(portsc) & XHCI_USB3_PORTSC_PLS; /* Reset all or only disconnected ports */ - usb_xhci_reset_port_usb3(mem_base, port); + if (all || status == XHCI_PLSR_RXDETECT) + usb_xhci_reset_port_usb3(mem_base, port); + else + port_disabled |= 1 << port; }
/* Wait for warm reset complete on all reset ports */ @@ -181,7 +184,7 @@ void usb_xhci_sleep_prepare(device_t dev, u8 slp_typ) write32(mem_base + 0x816c, reg32);
/* Reset disconnected USB3 ports */ - usb_xhci_reset_usb3(dev); + usb_xhci_reset_usb3(dev, 0);
/* Set MMIO 0x80e0[15] */ reg32 = read32(mem_base + 0x80e0); @@ -233,7 +236,7 @@ void usb_xhci_route_all(void) usb_ehci_disable(PCH_EHCI2_DEV);
/* Reset and clear port change status */ - usb_xhci_reset_usb3(PCH_XHCI_DEV); + usb_xhci_reset_usb3(PCH_XHCI_DEV, 1); }
#else /* !__SMM__ */ @@ -285,81 +288,6 @@ static void usb_xhci_clock_gating(device_t dev) pci_write_config32(dev, 0xa4, reg32); }
-/* Re-enable ports that are disabled */ -static void usb_xhci_enable_ports_usb3(device_t dev) -{ -#if CONFIG_FINALIZE_USB_ROUTE_XHCI - int port; - u32 portsc, status, disabled; - u32 mem_base = usb_xhci_mem_base(dev); - int port_count = usb_xhci_port_count_usb3(dev); - u8 port_reset = 0; - int timeout; - - if (!mem_base || !port_count) - return; - - /* Get port disable override map */ - disabled = pci_read_config32(dev, XHCI_USB3PDO); - - for (port = 0; port < port_count; port++) { - /* Skip overridden ports */ - if (disabled & (1 << port)) - continue; - portsc = mem_base + XHCI_USB3_PORTSC(port); - status = read32(portsc) & XHCI_USB3_PORTSC_PLS; - switch (status) { - case XHCI_PLSR_RXDETECT: - /* Clear change status */ - printk(BIOS_DEBUG, "usb_xhci reset status %d\n", port); - usb_xhci_reset_status_usb3(mem_base, port); - break; - case XHCI_PLSR_DISABLED: - default: - /* Reset port */ - printk(BIOS_DEBUG, "usb_xhci reset port %d\n", port); - usb_xhci_reset_port_usb3(mem_base, port); - port_reset |= 1 << port; - break; - } - } - - if (!port_reset) - return; - - /* Wait for warm reset complete on all reset ports */ - for (timeout = XHCI_RESET_TIMEOUT; timeout; timeout--) { - int complete = 1; - for (port = 0; port < port_count; port++) { - /* Only check ports that were reset */ - if (!(port_reset & (1 << port))) - continue; - /* Check if warm reset is complete */ - status = read32(mem_base + XHCI_USB3_PORTSC(port)); - if (!(status & XHCI_USB3_PORTSC_WRC)) - complete = 0; - } - /* Check for warm reset complete in any port */ - if (complete) - break; - udelay(XHCI_RESET_DELAY_US); - } - - /* Enable ports that were reset */ - for (port = 0; port < port_count; port++) { - /* Only check ports that were reset */ - if (!(port_reset & (1 << port))) - continue; - /* Transition to enabled */ - portsc = mem_base + XHCI_USB3_PORTSC(port); - status = read32(portsc); - status &= ~(XHCI_USB3_PORTSC_PLS | XHCI_USB3_PORTSC_PED); - status |= XHCI_PLSW_ENABLE | XHCI_USB3_PORTSC_LWS; - write32(portsc, status); - } -#endif -} - static void usb_xhci_init(device_t dev) { u32 reg32;