diff options
Diffstat (limited to 'drivers/usb/dwc3/dwc3-pci.c')
| -rw-r--r-- | drivers/usb/dwc3/dwc3-pci.c | 223 | 
1 files changed, 134 insertions, 89 deletions
| diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index c961a94d136b..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 @@ -34,18 +32,24 @@  #define PCI_DEVICE_ID_INTEL_GLK			0x31aa  #define PCI_DEVICE_ID_INTEL_CNPLP		0x9dee  #define PCI_DEVICE_ID_INTEL_CNPH		0xa36e +#define PCI_DEVICE_ID_INTEL_ICLLP		0x34ee  #define PCI_INTEL_BXT_DSM_GUID		"732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511"  #define PCI_INTEL_BXT_FUNC_PMU_PWR	4  #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; @@ -66,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); @@ -120,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); @@ -127,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;  } @@ -184,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; @@ -229,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; @@ -256,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 @@ -265,31 +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_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); |