diff options
| -rw-r--r-- | drivers/usb/host/xhci-pci.c | 40 |
1 files changed, 37 insertions, 3 deletions
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index da10dc728acb..5590eac2b22d 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c | |||
| @@ -28,6 +28,10 @@ | |||
| 28 | #include "xhci.h" | 28 | #include "xhci.h" |
| 29 | #include "xhci-trace.h" | 29 | #include "xhci-trace.h" |
| 30 | 30 | ||
| 31 | #define PORT2_SSIC_CONFIG_REG2 0x883c | ||
| 32 | #define PROG_DONE (1 << 30) | ||
| 33 | #define SSIC_PORT_UNUSED (1 << 31) | ||
| 34 | |||
| 31 | /* Device for a quirk */ | 35 | /* Device for a quirk */ |
| 32 | #define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 | 36 | #define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73 |
| 33 | #define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 | 37 | #define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000 |
| @@ -177,14 +181,44 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) | |||
| 177 | } | 181 | } |
| 178 | 182 | ||
| 179 | /* | 183 | /* |
| 184 | * In some Intel xHCI controllers, in order to get D3 working, | ||
| 185 | * through a vendor specific SSIC CONFIG register at offset 0x883c, | ||
| 186 | * SSIC PORT need to be marked as "unused" before putting xHCI | ||
| 187 | * into D3. After D3 exit, the SSIC port need to be marked as "used". | ||
| 188 | * Without this change, xHCI might not enter D3 state. | ||
| 180 | * Make sure PME works on some Intel xHCI controllers by writing 1 to clear | 189 | * Make sure PME works on some Intel xHCI controllers by writing 1 to clear |
| 181 | * the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4 | 190 | * the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4 |
| 182 | */ | 191 | */ |
| 183 | static void xhci_pme_quirk(struct xhci_hcd *xhci) | 192 | static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend) |
| 184 | { | 193 | { |
| 194 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | ||
| 195 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); | ||
| 185 | u32 val; | 196 | u32 val; |
| 186 | void __iomem *reg; | 197 | void __iomem *reg; |
| 187 | 198 | ||
| 199 | if (pdev->vendor == PCI_VENDOR_ID_INTEL && | ||
| 200 | pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) { | ||
| 201 | |||
| 202 | reg = (void __iomem *) xhci->cap_regs + PORT2_SSIC_CONFIG_REG2; | ||
| 203 | |||
| 204 | /* Notify SSIC that SSIC profile programming is not done */ | ||
| 205 | val = readl(reg) & ~PROG_DONE; | ||
| 206 | writel(val, reg); | ||
| 207 | |||
| 208 | /* Mark SSIC port as unused(suspend) or used(resume) */ | ||
| 209 | val = readl(reg); | ||
| 210 | if (suspend) | ||
| 211 | val |= SSIC_PORT_UNUSED; | ||
| 212 | else | ||
| 213 | val &= ~SSIC_PORT_UNUSED; | ||
| 214 | writel(val, reg); | ||
| 215 | |||
| 216 | /* Notify SSIC that SSIC profile programming is done */ | ||
| 217 | val = readl(reg) | PROG_DONE; | ||
| 218 | writel(val, reg); | ||
| 219 | readl(reg); | ||
| 220 | } | ||
| 221 | |||
| 188 | reg = (void __iomem *) xhci->cap_regs + 0x80a4; | 222 | reg = (void __iomem *) xhci->cap_regs + 0x80a4; |
| 189 | val = readl(reg); | 223 | val = readl(reg); |
| 190 | writel(val | BIT(28), reg); | 224 | writel(val | BIT(28), reg); |
| @@ -324,7 +358,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) | |||
| 324 | pdev->no_d3cold = true; | 358 | pdev->no_d3cold = true; |
| 325 | 359 | ||
| 326 | if (xhci->quirks & XHCI_PME_STUCK_QUIRK) | 360 | if (xhci->quirks & XHCI_PME_STUCK_QUIRK) |
| 327 | xhci_pme_quirk(xhci); | 361 | xhci_pme_quirk(hcd, true); |
| 328 | 362 | ||
| 329 | return xhci_suspend(xhci, do_wakeup); | 363 | return xhci_suspend(xhci, do_wakeup); |
| 330 | } | 364 | } |
| @@ -357,7 +391,7 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) | |||
| 357 | usb_enable_intel_xhci_ports(pdev); | 391 | usb_enable_intel_xhci_ports(pdev); |
| 358 | 392 | ||
| 359 | if (xhci->quirks & XHCI_PME_STUCK_QUIRK) | 393 | if (xhci->quirks & XHCI_PME_STUCK_QUIRK) |
| 360 | xhci_pme_quirk(xhci); | 394 | xhci_pme_quirk(hcd, false); |
| 361 | 395 | ||
| 362 | retval = xhci_resume(xhci, hibernated); | 396 | retval = xhci_resume(xhci, hibernated); |
| 363 | return retval; | 397 | return retval; |
