diff options
Diffstat (limited to 'drivers/usb/host/xhci-pci.c')
-rw-r--r-- | drivers/usb/host/xhci-pci.c | 56 |
1 files changed, 42 insertions, 14 deletions
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 58c43ed7ff3b..f0640b7a1c42 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c | |||
@@ -28,7 +28,9 @@ | |||
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 | 31 | #define SSIC_PORT_NUM 2 |
32 | #define SSIC_PORT_CFG2 0x880c | ||
33 | #define SSIC_PORT_CFG2_OFFSET 0x30 | ||
32 | #define PROG_DONE (1 << 30) | 34 | #define PROG_DONE (1 << 30) |
33 | #define SSIC_PORT_UNUSED (1 << 31) | 35 | #define SSIC_PORT_UNUSED (1 << 31) |
34 | 36 | ||
@@ -45,6 +47,7 @@ | |||
45 | #define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI 0x22b5 | 47 | #define PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI 0x22b5 |
46 | #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI 0xa12f | 48 | #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI 0xa12f |
47 | #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI 0x9d2f | 49 | #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI 0x9d2f |
50 | #define PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI 0x0aa8 | ||
48 | 51 | ||
49 | static const char hcd_name[] = "xhci_hcd"; | 52 | static const char hcd_name[] = "xhci_hcd"; |
50 | 53 | ||
@@ -151,9 +154,14 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) | |||
151 | if (pdev->vendor == PCI_VENDOR_ID_INTEL && | 154 | if (pdev->vendor == PCI_VENDOR_ID_INTEL && |
152 | (pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || | 155 | (pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI || |
153 | pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI || | 156 | pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI || |
154 | pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI)) { | 157 | pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || |
158 | pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI)) { | ||
155 | xhci->quirks |= XHCI_PME_STUCK_QUIRK; | 159 | xhci->quirks |= XHCI_PME_STUCK_QUIRK; |
156 | } | 160 | } |
161 | if (pdev->vendor == PCI_VENDOR_ID_INTEL && | ||
162 | pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) { | ||
163 | xhci->quirks |= XHCI_SSIC_PORT_UNUSED; | ||
164 | } | ||
157 | if (pdev->vendor == PCI_VENDOR_ID_ETRON && | 165 | if (pdev->vendor == PCI_VENDOR_ID_ETRON && |
158 | pdev->device == PCI_DEVICE_ID_EJ168) { | 166 | pdev->device == PCI_DEVICE_ID_EJ168) { |
159 | xhci->quirks |= XHCI_RESET_ON_RESUME; | 167 | xhci->quirks |= XHCI_RESET_ON_RESUME; |
@@ -312,22 +320,20 @@ static void xhci_pci_remove(struct pci_dev *dev) | |||
312 | * SSIC PORT need to be marked as "unused" before putting xHCI | 320 | * SSIC PORT need to be marked as "unused" before putting xHCI |
313 | * into D3. After D3 exit, the SSIC port need to be marked as "used". | 321 | * into D3. After D3 exit, the SSIC port need to be marked as "used". |
314 | * Without this change, xHCI might not enter D3 state. | 322 | * Without this change, xHCI might not enter D3 state. |
315 | * Make sure PME works on some Intel xHCI controllers by writing 1 to clear | ||
316 | * the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4 | ||
317 | */ | 323 | */ |
318 | static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend) | 324 | static void xhci_ssic_port_unused_quirk(struct usb_hcd *hcd, bool suspend) |
319 | { | 325 | { |
320 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 326 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
321 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); | ||
322 | u32 val; | 327 | u32 val; |
323 | void __iomem *reg; | 328 | void __iomem *reg; |
329 | int i; | ||
324 | 330 | ||
325 | if (pdev->vendor == PCI_VENDOR_ID_INTEL && | 331 | for (i = 0; i < SSIC_PORT_NUM; i++) { |
326 | pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI) { | 332 | reg = (void __iomem *) xhci->cap_regs + |
327 | 333 | SSIC_PORT_CFG2 + | |
328 | reg = (void __iomem *) xhci->cap_regs + PORT2_SSIC_CONFIG_REG2; | 334 | i * SSIC_PORT_CFG2_OFFSET; |
329 | 335 | ||
330 | /* Notify SSIC that SSIC profile programming is not done */ | 336 | /* Notify SSIC that SSIC profile programming is not done. */ |
331 | val = readl(reg) & ~PROG_DONE; | 337 | val = readl(reg) & ~PROG_DONE; |
332 | writel(val, reg); | 338 | writel(val, reg); |
333 | 339 | ||
@@ -344,6 +350,17 @@ static void xhci_pme_quirk(struct usb_hcd *hcd, bool suspend) | |||
344 | writel(val, reg); | 350 | writel(val, reg); |
345 | readl(reg); | 351 | readl(reg); |
346 | } | 352 | } |
353 | } | ||
354 | |||
355 | /* | ||
356 | * Make sure PME works on some Intel xHCI controllers by writing 1 to clear | ||
357 | * the Internal PME flag bit in vendor specific PMCTRL register at offset 0x80a4 | ||
358 | */ | ||
359 | static void xhci_pme_quirk(struct usb_hcd *hcd) | ||
360 | { | ||
361 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | ||
362 | void __iomem *reg; | ||
363 | u32 val; | ||
347 | 364 | ||
348 | reg = (void __iomem *) xhci->cap_regs + 0x80a4; | 365 | reg = (void __iomem *) xhci->cap_regs + 0x80a4; |
349 | val = readl(reg); | 366 | val = readl(reg); |
@@ -355,6 +372,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) | |||
355 | { | 372 | { |
356 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 373 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
357 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); | 374 | struct pci_dev *pdev = to_pci_dev(hcd->self.controller); |
375 | int ret; | ||
358 | 376 | ||
359 | /* | 377 | /* |
360 | * Systems with the TI redriver that loses port status change events | 378 | * Systems with the TI redriver that loses port status change events |
@@ -364,9 +382,16 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) | |||
364 | pdev->no_d3cold = true; | 382 | pdev->no_d3cold = true; |
365 | 383 | ||
366 | if (xhci->quirks & XHCI_PME_STUCK_QUIRK) | 384 | if (xhci->quirks & XHCI_PME_STUCK_QUIRK) |
367 | xhci_pme_quirk(hcd, true); | 385 | xhci_pme_quirk(hcd); |
386 | |||
387 | if (xhci->quirks & XHCI_SSIC_PORT_UNUSED) | ||
388 | xhci_ssic_port_unused_quirk(hcd, true); | ||
368 | 389 | ||
369 | return xhci_suspend(xhci, do_wakeup); | 390 | ret = xhci_suspend(xhci, do_wakeup); |
391 | if (ret && (xhci->quirks & XHCI_SSIC_PORT_UNUSED)) | ||
392 | xhci_ssic_port_unused_quirk(hcd, false); | ||
393 | |||
394 | return ret; | ||
370 | } | 395 | } |
371 | 396 | ||
372 | static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) | 397 | static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) |
@@ -396,8 +421,11 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) | |||
396 | if (pdev->vendor == PCI_VENDOR_ID_INTEL) | 421 | if (pdev->vendor == PCI_VENDOR_ID_INTEL) |
397 | usb_enable_intel_xhci_ports(pdev); | 422 | usb_enable_intel_xhci_ports(pdev); |
398 | 423 | ||
424 | if (xhci->quirks & XHCI_SSIC_PORT_UNUSED) | ||
425 | xhci_ssic_port_unused_quirk(hcd, false); | ||
426 | |||
399 | if (xhci->quirks & XHCI_PME_STUCK_QUIRK) | 427 | if (xhci->quirks & XHCI_PME_STUCK_QUIRK) |
400 | xhci_pme_quirk(hcd, false); | 428 | xhci_pme_quirk(hcd); |
401 | 429 | ||
402 | retval = xhci_resume(xhci, hibernated); | 430 | retval = xhci_resume(xhci, hibernated); |
403 | return retval; | 431 | return retval; |