aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/xhci-pci.c40
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 */
183static void xhci_pme_quirk(struct xhci_hcd *xhci) 192static 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;