summaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3/dwc3-pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc3/dwc3-pci.c')
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c223
1 files changed, 133 insertions, 90 deletions
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index f57e7c94b8e5..5edd79470368 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -16,12 +16,10 @@
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
#include <linux/acpi.h>
#include <linux/delay.h>
-#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
-#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI 0xabce
-#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31 0xabcf
#define PCI_DEVICE_ID_INTEL_BYT 0x0f37
#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e
#define PCI_DEVICE_ID_INTEL_BSW 0x22b7
@@ -41,12 +39,17 @@
#define PCI_INTEL_BXT_STATE_D0 0
#define PCI_INTEL_BXT_STATE_D3 3
+#define GP_RWBAR 1
+#define GP_RWREG1 0xa0
+#define GP_RWREG1_ULPI_REFCLK_DISABLE (1 << 17)
+
/**
* struct dwc3_pci - Driver private structure
* @dwc3: child dwc3 platform_device
* @pci: our link to PCI bus
* @guid: _DSM GUID
* @has_dsm_for_pm: true for devices which need to run _DSM on runtime PM
+ * @wakeup_work: work for asynchronous resume
*/
struct dwc3_pci {
struct platform_device *dwc3;
@@ -67,52 +70,74 @@ static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
{ },
};
-static int dwc3_pci_quirks(struct dwc3_pci *dwc)
+static struct gpiod_lookup_table platform_bytcr_gpios = {
+ .dev_id = "0000:00:16.0",
+ .table = {
+ GPIO_LOOKUP("INT33FC:00", 54, "reset", GPIO_ACTIVE_HIGH),
+ GPIO_LOOKUP("INT33FC:02", 14, "cs", GPIO_ACTIVE_HIGH),
+ {}
+ },
+};
+
+static int dwc3_byt_enable_ulpi_refclock(struct pci_dev *pci)
{
- struct platform_device *dwc3 = dwc->dwc3;
- struct pci_dev *pdev = dwc->pci;
+ void __iomem *reg;
+ u32 value;
+
+ reg = pcim_iomap(pci, GP_RWBAR, 0);
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+ value = readl(reg + GP_RWREG1);
+ if (!(value & GP_RWREG1_ULPI_REFCLK_DISABLE))
+ goto unmap; /* ULPI refclk already enabled */
+
+ value &= ~GP_RWREG1_ULPI_REFCLK_DISABLE;
+ writel(value, reg + GP_RWREG1);
+ /* This comes from the Intel Android x86 tree w/o any explanation */
+ msleep(100);
+unmap:
+ pcim_iounmap(pci, reg);
+ return 0;
+}
- if (pdev->vendor == PCI_VENDOR_ID_AMD &&
- pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
- struct property_entry properties[] = {
- PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
- PROPERTY_ENTRY_U8("snps,lpm-nyet-threshold", 0xf),
- PROPERTY_ENTRY_BOOL("snps,u2exit_lfps_quirk"),
- PROPERTY_ENTRY_BOOL("snps,u2ss_inp3_quirk"),
- PROPERTY_ENTRY_BOOL("snps,req_p1p2p3_quirk"),
- PROPERTY_ENTRY_BOOL("snps,del_p1p2p3_quirk"),
- PROPERTY_ENTRY_BOOL("snps,del_phy_power_chg_quirk"),
- PROPERTY_ENTRY_BOOL("snps,lfps_filter_quirk"),
- PROPERTY_ENTRY_BOOL("snps,rx_detect_poll_quirk"),
- PROPERTY_ENTRY_BOOL("snps,tx_de_emphasis_quirk"),
- PROPERTY_ENTRY_U8("snps,tx_de_emphasis", 1),
- /*
- * FIXME these quirks should be removed when AMD NL
- * tapes out
- */
- PROPERTY_ENTRY_BOOL("snps,disable_scramble_quirk"),
- PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
- PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
- PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
- { },
- };
-
- return platform_device_add_properties(dwc3, properties);
- }
+static const struct property_entry dwc3_pci_intel_properties[] = {
+ PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
+ PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
+ {}
+};
- if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
- int ret;
+static const struct property_entry dwc3_pci_mrfld_properties[] = {
+ PROPERTY_ENTRY_STRING("dr_mode", "otg"),
+ PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
+ {}
+};
- struct property_entry properties[] = {
- PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
- PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
- { }
- };
+static const struct property_entry dwc3_pci_amd_properties[] = {
+ PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
+ PROPERTY_ENTRY_U8("snps,lpm-nyet-threshold", 0xf),
+ PROPERTY_ENTRY_BOOL("snps,u2exit_lfps_quirk"),
+ PROPERTY_ENTRY_BOOL("snps,u2ss_inp3_quirk"),
+ PROPERTY_ENTRY_BOOL("snps,req_p1p2p3_quirk"),
+ PROPERTY_ENTRY_BOOL("snps,del_p1p2p3_quirk"),
+ PROPERTY_ENTRY_BOOL("snps,del_phy_power_chg_quirk"),
+ PROPERTY_ENTRY_BOOL("snps,lfps_filter_quirk"),
+ PROPERTY_ENTRY_BOOL("snps,rx_detect_poll_quirk"),
+ PROPERTY_ENTRY_BOOL("snps,tx_de_emphasis_quirk"),
+ PROPERTY_ENTRY_U8("snps,tx_de_emphasis", 1),
+ /* FIXME these quirks should be removed when AMD NL tapes out */
+ PROPERTY_ENTRY_BOOL("snps,disable_scramble_quirk"),
+ PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
+ PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
+ PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
+ {}
+};
- ret = platform_device_add_properties(dwc3, properties);
- if (ret < 0)
- return ret;
+static int dwc3_pci_quirks(struct dwc3_pci *dwc)
+{
+ struct pci_dev *pdev = dwc->pci;
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
if (pdev->device == PCI_DEVICE_ID_INTEL_BXT ||
pdev->device == PCI_DEVICE_ID_INTEL_BXT_M) {
guid_parse(PCI_INTEL_BXT_DSM_GUID, &dwc->guid);
@@ -121,6 +146,12 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
struct gpio_desc *gpio;
+ int ret;
+
+ /* On BYT the FW does not always enable the refclock */
+ ret = dwc3_byt_enable_ulpi_refclock(pdev);
+ if (ret)
+ return ret;
ret = devm_acpi_dev_add_driver_gpios(&pdev->dev,
acpi_dwc3_byt_gpios);
@@ -128,44 +159,36 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
dev_dbg(&pdev->dev, "failed to add mapping table\n");
/*
+ * A lot of BYT devices lack ACPI resource entries for
+ * the GPIOs, add a fallback mapping to the reference
+ * design GPIOs which all boards seem to use.
+ */
+ gpiod_add_lookup_table(&platform_bytcr_gpios);
+
+ /*
* These GPIOs will turn on the USB2 PHY. Note that we have to
* put the gpio descriptors again here because the phy driver
* might want to grab them, too.
*/
- gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
+ gpio = devm_gpiod_get_optional(&pdev->dev, "cs",
+ GPIOD_OUT_LOW);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
gpiod_set_value_cansleep(gpio, 1);
- gpiod_put(gpio);
- gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
+ gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
+ GPIOD_OUT_LOW);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
if (gpio) {
gpiod_set_value_cansleep(gpio, 1);
- gpiod_put(gpio);
usleep_range(10000, 11000);
}
}
}
- if (pdev->vendor == PCI_VENDOR_ID_SYNOPSYS &&
- (pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 ||
- pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI ||
- pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31)) {
- struct property_entry properties[] = {
- PROPERTY_ENTRY_BOOL("snps,usb3_lpm_capable"),
- PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
- PROPERTY_ENTRY_BOOL("snps,dis_enblslpm_quirk"),
- PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
- { },
- };
-
- return platform_device_add_properties(dwc3, properties);
- }
-
return 0;
}
@@ -185,9 +208,9 @@ static void dwc3_pci_resume_work(struct work_struct *work)
}
#endif
-static int dwc3_pci_probe(struct pci_dev *pci,
- const struct pci_device_id *id)
+static int dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
{
+ struct property_entry *p = (struct property_entry *)id->driver_data;
struct dwc3_pci *dwc;
struct resource res[2];
int ret;
@@ -230,6 +253,10 @@ static int dwc3_pci_probe(struct pci_dev *pci,
dwc->dwc3->dev.parent = dev;
ACPI_COMPANION_SET(&dwc->dwc3->dev, ACPI_COMPANION(dev));
+ ret = platform_device_add_properties(dwc->dwc3, p);
+ if (ret < 0)
+ return ret;
+
ret = dwc3_pci_quirks(dwc);
if (ret)
goto err;
@@ -257,6 +284,7 @@ static void dwc3_pci_remove(struct pci_dev *pci)
{
struct dwc3_pci *dwc = pci_get_drvdata(pci);
+ gpiod_remove_lookup_table(&platform_bytcr_gpios);
#ifdef CONFIG_PM
cancel_work_sync(&dwc->wakeup_work);
#endif
@@ -266,32 +294,47 @@ static void dwc3_pci_remove(struct pci_dev *pci)
}
static const struct pci_device_id dwc3_pci_id_table[] = {
- {
- PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
- PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
- },
- {
- PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
- PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI),
- },
- {
- PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
- PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31),
- },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_M), },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBP), },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GLK), },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPLP), },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPH), },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICLLP), },
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BSW),
+ (kernel_ulong_t) &dwc3_pci_intel_properties },
+
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BYT),
+ (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD),
+ (kernel_ulong_t) &dwc3_pci_mrfld_properties, },
+
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTLP),
+ (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTH),
+ (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT),
+ (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT_M),
+ (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_APL),
+ (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_KBP),
+ (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_GLK),
+ (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPLP),
+ (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPH),
+ (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP),
+ (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB),
+ (kernel_ulong_t) &dwc3_pci_amd_properties, },
{ } /* Terminating Entry */
};
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);