1 /** 2 * dwc3-pci.c - PCI Specific glue layer 3 * 4 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com 5 * 6 * Authors: Felipe Balbi <balbi@ti.com>, 7 * Sebastian Andrzej Siewior <bigeasy@linutronix.de> 8 * 9 * This program is free software: you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 of 11 * the License as published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 */ 18 19 #include <linux/kernel.h> 20 #include <linux/module.h> 21 #include <linux/slab.h> 22 #include <linux/pci.h> 23 #include <linux/platform_device.h> 24 25 #include "platform_data.h" 26 27 /* FIXME define these in <linux/pci_ids.h> */ 28 #define PCI_VENDOR_ID_SYNOPSYS 0x16c3 29 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd 30 #define PCI_DEVICE_ID_INTEL_BYT 0x0f37 31 #define PCI_DEVICE_ID_INTEL_MRFLD 0x119e 32 #define PCI_DEVICE_ID_INTEL_BSW 0x22B7 33 #define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30 34 #define PCI_DEVICE_ID_INTEL_SPTH 0xa130 35 36 static int dwc3_pci_quirks(struct pci_dev *pdev) 37 { 38 if (pdev->vendor == PCI_VENDOR_ID_AMD && 39 pdev->device == PCI_DEVICE_ID_AMD_NL_USB) { 40 struct dwc3_platform_data pdata; 41 42 memset(&pdata, 0, sizeof(pdata)); 43 44 pdata.has_lpm_erratum = true; 45 pdata.lpm_nyet_threshold = 0xf; 46 47 pdata.u2exit_lfps_quirk = true; 48 pdata.u2ss_inp3_quirk = true; 49 pdata.req_p1p2p3_quirk = true; 50 pdata.del_p1p2p3_quirk = true; 51 pdata.del_phy_power_chg_quirk = true; 52 pdata.lfps_filter_quirk = true; 53 pdata.rx_detect_poll_quirk = true; 54 55 pdata.tx_de_emphasis_quirk = true; 56 pdata.tx_de_emphasis = 1; 57 58 /* 59 * FIXME these quirks should be removed when AMD NL 60 * taps out 61 */ 62 pdata.disable_scramble_quirk = true; 63 pdata.dis_u3_susphy_quirk = true; 64 pdata.dis_u2_susphy_quirk = true; 65 66 return platform_device_add_data(pci_get_drvdata(pdev), &pdata, 67 sizeof(pdata)); 68 } 69 70 return 0; 71 } 72 73 static int dwc3_pci_probe(struct pci_dev *pci, 74 const struct pci_device_id *id) 75 { 76 struct resource res[2]; 77 struct platform_device *dwc3; 78 int ret; 79 struct device *dev = &pci->dev; 80 81 ret = pcim_enable_device(pci); 82 if (ret) { 83 dev_err(dev, "failed to enable pci device\n"); 84 return -ENODEV; 85 } 86 87 pci_set_master(pci); 88 89 dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO); 90 if (!dwc3) { 91 dev_err(dev, "couldn't allocate dwc3 device\n"); 92 return -ENOMEM; 93 } 94 95 memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); 96 97 res[0].start = pci_resource_start(pci, 0); 98 res[0].end = pci_resource_end(pci, 0); 99 res[0].name = "dwc_usb3"; 100 res[0].flags = IORESOURCE_MEM; 101 102 res[1].start = pci->irq; 103 res[1].name = "dwc_usb3"; 104 res[1].flags = IORESOURCE_IRQ; 105 106 ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res)); 107 if (ret) { 108 dev_err(dev, "couldn't add resources to dwc3 device\n"); 109 return ret; 110 } 111 112 pci_set_drvdata(pci, dwc3); 113 ret = dwc3_pci_quirks(pci); 114 if (ret) 115 goto err; 116 117 dwc3->dev.parent = dev; 118 119 ret = platform_device_add(dwc3); 120 if (ret) { 121 dev_err(dev, "failed to register dwc3 device\n"); 122 goto err; 123 } 124 125 return 0; 126 err: 127 platform_device_put(dwc3); 128 return ret; 129 } 130 131 static void dwc3_pci_remove(struct pci_dev *pci) 132 { 133 platform_device_unregister(pci_get_drvdata(pci)); 134 } 135 136 static const struct pci_device_id dwc3_pci_id_table[] = { 137 { 138 PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, 139 PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3), 140 }, 141 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), }, 142 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), }, 143 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), }, 144 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), }, 145 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), }, 146 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), }, 147 { } /* Terminating Entry */ 148 }; 149 MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); 150 151 static struct pci_driver dwc3_pci_driver = { 152 .name = "dwc3-pci", 153 .id_table = dwc3_pci_id_table, 154 .probe = dwc3_pci_probe, 155 .remove = dwc3_pci_remove, 156 }; 157 158 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>"); 159 MODULE_LICENSE("GPL v2"); 160 MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer"); 161 162 module_pci_driver(dwc3_pci_driver); 163