提交 abce329c 编写于 作者: R Rajmohan Mani 提交者: Greg Kroah-Hartman

xhci: Workaround to get D3 working in Intel xHCI

The xHCI in Intel CherryView / Braswell Platform requires
a driver workaround to get xHCI D3 working. Without this
workaround, xHCI might not enter D3.

Workaround is to configure SSIC PORT as "unused" before D3
entry and "used" after D3 exit. This is done through a
vendor specific register (PORT2_SSIC_CONFIG_REG2 at offset
0x883c), in xhci suspend / resume callbacks.

Verified xHCI D3 works fine in CherryView / Braswell platform.
Signed-off-by: NRajmohan Mani <rajmohan.mani@intel.com>
Signed-off-by: NMathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
上级 c3c5819a
......@@ -28,6 +28,10 @@
#include "xhci.h"
#include "xhci-trace.h"
#define PORT2_SSIC_CONFIG_REG2 0x883c
#define PROG_DONE (1 << 30)
#define SSIC_PORT_UNUSED (1 << 31)
/* Device for a quirk */
#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73
#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000
......@@ -177,14 +181,44 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
}
/*
* In some Intel xHCI controllers, in order to get D3 working,
* through a vendor specific SSIC CONFIG register at offset 0x883c,
* SSIC PORT need to be marked as "unused" before putting xHCI
* into D3. After D3 exit, the SSIC port need to be marked as "used".
* Without this change, xHCI might not enter D3 state.
* Make sure PME works on some Intel xHCI controllers by writing 1 to clear
* the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4
*/
static void xhci_pme_quirk(struct xhci_hcd *xhci)
static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
u32 val;
void __iomem *reg;
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) {
reg = (void __iomem *) xhci->cap_regs + PORT2_SSIC_CONFIG_REG2;
/* Notify SSIC that SSIC profile programming is not done */
val = readl(reg) & ~PROG_DONE;
writel(val, reg);
/* Mark SSIC port as unused(suspend) or used(resume) */
val = readl(reg);
if (suspend)
val |= SSIC_PORT_UNUSED;
else
val &= ~SSIC_PORT_UNUSED;
writel(val, reg);
/* Notify SSIC that SSIC profile programming is done */
val = readl(reg) | PROG_DONE;
writel(val, reg);
readl(reg);
}
reg = (void __iomem *) xhci->cap_regs + 0x80a4;
val = readl(reg);
writel(val | BIT(28), reg);
......@@ -324,7 +358,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
pdev->no_d3cold = true;
if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
xhci_pme_quirk(xhci);
xhci_pme_quirk(hcd, true);
return xhci_suspend(xhci, do_wakeup);
}
......@@ -357,7 +391,7 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
usb_enable_intel_xhci_ports(pdev);
if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
xhci_pme_quirk(xhci);
xhci_pme_quirk(hcd, false);
retval = xhci_resume(xhci, hibernated);
return retval;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册