Signed-off-by: Joe Lee <[email protected]>
---
drivers/usb/host/pci-quirks.c | 128 ++++++++++++++++++++++++++++++++++++++++++
drivers/usb/host/pci-quirks.h | 5 ++
drivers/usb/host/xhci-hub.c | 7 +++
drivers/usb/host/xhci-pci.c | 11 ++++
drivers/usb/host/xhci.h | 2 +-
5 files changed, 152 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 6dda362..d66a2c6 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -65,6 +65,23 @@
#define AX_INDXC 0x30
#define AX_DATAC 0x34
+#define PT_ADDR_INDX 0xE8
+#define PT_READ_INDX 0xE4
+#define PT_SIG_1_ADDR 0xA520
+#define PT_SIG_2_ADDR 0xA521
+#define PT_SIG_3_ADDR 0xA522
+#define PT_SIG_4_ADDR 0xA523
+#define PT_SIG_1_DATA 0x78
+#define PT_SIG_2_DATA 0x56
+#define PT_SIG_3_DATA 0x34
+#define PT_SIG_4_DATA 0x12
+#define PT4_P1_REG 0xB521
+#define PT4_P2_REG 0xB522
+#define PT2_P1_REG 0xD520
+#define PT2_P2_REG 0xD521
+#define PT1_P1_REG 0xD522
+#define PT1_P2_REG 0xD523
+
#define NB_PCIE_INDX_ADDR 0xe0
#define NB_PCIE_INDX_DATA 0xe4
#define PCIE_P_CNTL 0x10040
@@ -511,6 +528,117 @@ void usb_amd_dev_put(void)
}
EXPORT_SYMBOL_GPL(usb_amd_dev_put);
+bool usb_amd_pt_check_port(struct device *device, int port)
+{
+ unsigned char value;
+ struct pci_dev *pdev;
+
+ pdev = to_pci_dev(device);
+ pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_1_ADDR);
+
+ pci_read_config_byte(pdev, PT_READ_INDX, &value);
+ if (value != PT_SIG_1_DATA)
+ return 0;
+
+ pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_2_ADDR);
+
+ pci_read_config_byte(pdev, PT_READ_INDX, &value);
+ if (value != PT_SIG_2_DATA)
+ return 0;
+
+ pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_3_ADDR);
+
+ pci_read_config_byte(pdev, PT_READ_INDX, &value);
+ if (value != PT_SIG_3_DATA)
+ return 0;
+
+ pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_4_ADDR);
+
+ pci_read_config_byte(pdev, PT_READ_INDX, &value);
+ if (value != PT_SIG_4_DATA)
+ return 0;
+
+ if ((pdev->device == 0x43b9) || (pdev->device == 0x43ba)) {
+ /* device is AMD_PROMONTORYA_4(0x43b9) or
+ * PROMONTORYA_3(0x43ba)
+ * disable port setting
+ * PT_4_P1_REG[7..1] is USB2.0 port6 to 0
+ * PT4_P2_REG[6..0] is USB 13 to port 7
+ * 0 : disable ;1 : enable
+ */
+ if (port > 6) {
+ pci_write_config_word(pdev, PT_ADDR_INDX,
+ PT4_P2_REG);
+
+ pci_read_config_byte(pdev, PT_READ_INDX, &value);
+ if (value & (1<<(port - 7)))
+ return 0;
+ else
+ return 1;
+ } else {
+ pci_write_config_word(pdev, PT_ADDR_INDX,
+ PT4_P1_REG);
+
+ pci_read_config_byte(pdev, PT_READ_INDX, &value);
+ if (value & (1<<(port + 1)))
+ return 0;
+ else
+ return 1;
+ }
+ } else if (pdev->device == 0x43bb) {
+ /* device is AMD_PROMONTORYA_2(0x43bb)
+ * disable port setting
+ * PT2_P1_REG[7..5] is USB2.0 port2 to 0
+ * PT2_P2_REG[5..0] is USB 9 to port3
+ * 0 : disable ;1 : enable
+ */
+ if (port > 2) {
+ pci_write_config_word(pdev, PT_ADDR_INDX, PT2_P2_REG);
+
+ pci_read_config_byte(pdev, PT_READ_INDX, &value);
+ if (value & (1<<(port - 3)))
+ return 0;
+ else
+ return 1;
+ } else {
+ pci_write_config_word(pdev, PT_ADDR_INDX, PT2_P1_REG);
+
+ pci_read_config_byte(pdev, PT_READ_INDX, &value);
+ if (value & (1<<(port + 5)))
+ return 0;
+ else
+ return 1;
+ }
+ } else {
+ /* device is AMD_PROMONTORYA_1(0x43bc)
+ * disable port setting
+ * PT1_P1_REG[7..4] is USB2.0 port3 to 0
+ * PT1_P2_REG[5..0] is USB 9 to port4
+ * 0 : disable ;1 : enable
+ */
+ if (port > 3) {
+ pci_write_config_word(pdev, PT_ADDR_INDX, PT1_P2_REG);
+
+ pci_read_config_byte(pdev, PT_READ_INDX, &value);
+ if (value & (1<<(port - 4)))
+ return 0;
+ else
+ return 1;
+
+ } else {
+ pci_write_config_word(pdev, PT_ADDR_INDX, PT1_P1_REG);
+
+ pci_read_config_byte(pdev, PT_READ_INDX, &value);
+ if (value & (1<<(port + 4)))
+ return 0;
+ else
+ return 1;
+
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(usb_amd_pt_check_port);
+
/*
* Make sure the controller is completely inactive, unable to
* generate interrupts or do DMA.
diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h
index b68dcb5..8f843e3 100644
--- a/drivers/usb/host/pci-quirks.h
+++ b/drivers/usb/host/pci-quirks.h
@@ -17,6 +17,7 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev);
void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
void sb800_prefetch(struct device *dev, int on);
bool usb_xhci_needs_pci_reset(struct pci_dev *pdev);
+bool usb_amd_pt_check_port(struct device *device, int port);
#else
struct pci_dev;
static inline void usb_amd_quirk_pll_disable(void) {}
@@ -25,6 +26,10 @@ static inline void usb_asmedia_modifyflowcontrol(struct
pci_dev *pdev) {}
static inline void usb_amd_dev_put(void) {}
static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {}
static inline void sb800_prefetch(struct device *dev, int on) {}
+static inline bool usb_amd_pt_check_port(struct device *device, int port)
+{
+ return 0;
+}
#endif /* CONFIG_USB_PCI */
#endif /* __LINUX_USB_PCI_QUIRKS_H */
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index a2336de..0df0497 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1528,6 +1528,13 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
t2 |= PORT_WKOC_E | PORT_WKCONN_E;
t2 &= ~PORT_WKDISC_E;
}
+
+ if ((xhci->quirks & XHCI_U2_DISABLE_WAKE) &&
+ (hcd->speed < HCD_USB3)) {
+ if (usb_amd_pt_check_port(hcd->self.controller,
+ port_index))
+ t2 &= ~PORT_WAKE_BITS;
+ }
} else
t2 &= ~PORT_WAKE_BITS;
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 76f3929..f056754 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -54,6 +54,10 @@
#define PCI_DEVICE_ID_INTEL_APL_XHCI 0x5aa8
#define PCI_DEVICE_ID_INTEL_DNV_XHCI 0x19d0
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_2 0x43bb
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_1 0x43bc
#define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI 0x1142
static const char hcd_name[] = "xhci_hcd";
@@ -137,6 +141,13 @@ static void xhci_pci_quirks(struct device *dev, struct
xhci_hcd *xhci)
if (pdev->vendor == PCI_VENDOR_ID_AMD)
xhci->quirks |= XHCI_TRUST_TX_LENGTH;
+ if ((pdev->vendor == PCI_VENDOR_ID_AMD) &&
+ ((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) ||
+ (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_3) ||
+ (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_2) ||
+ (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_1)))
+ xhci->quirks |= XHCI_U2_DISABLE_WAKE;
+
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
xhci->quirks |= XHCI_LPM_SUPPORT;
xhci->quirks |= XHCI_INTEL_HOST;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 2b48aa4..7c87189 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1828,7 +1828,7 @@ struct xhci_hcd {
/* For controller with a broken Port Disable implementation */
#define XHCI_BROKEN_PORT_PED (1 << 25)
#define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26)
-/* Reserved. It was XHCI_U2_DISABLE_WAKE */
+#define XHCI_U2_DISABLE_WAKE (1 << 27)
#define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28)
unsigned int num_active_eps;
--
2.7.4
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html