1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Cadence USBSS PCI Glue driver 4 * 5 * Copyright (C) 2018-2019 Cadence. 6 * 7 * Author: Pawel Laszczak <pawell@cadence.com> 8 */ 9 10 #include <linux/kernel.h> 11 #include <linux/module.h> 12 #include <linux/pci.h> 13 #include <linux/platform_device.h> 14 #include <linux/dma-mapping.h> 15 #include <linux/slab.h> 16 17 struct cdns3_wrap { 18 struct platform_device *plat_dev; 19 struct resource dev_res[6]; 20 int devfn; 21 }; 22 23 #define RES_IRQ_HOST_ID 0 24 #define RES_IRQ_PERIPHERAL_ID 1 25 #define RES_IRQ_OTG_ID 2 26 #define RES_HOST_ID 3 27 #define RES_DEV_ID 4 28 #define RES_DRD_ID 5 29 30 #define PCI_BAR_HOST 0 31 #define PCI_BAR_DEV 2 32 #define PCI_BAR_OTG 0 33 34 #define PCI_DEV_FN_HOST_DEVICE 0 35 #define PCI_DEV_FN_OTG 1 36 37 #define PCI_DRIVER_NAME "cdns3-pci-usbss" 38 #define PLAT_DRIVER_NAME "cdns-usb3" 39 40 #define CDNS_VENDOR_ID 0x17cd 41 #define CDNS_DEVICE_ID 0x0100 42 43 static struct pci_dev *cdns3_get_second_fun(struct pci_dev *pdev) 44 { 45 struct pci_dev *func; 46 47 /* 48 * Gets the second function. 49 * It's little tricky, but this platform has two function. 50 * The fist keeps resources for Host/Device while the second 51 * keeps resources for DRD/OTG. 52 */ 53 func = pci_get_device(pdev->vendor, pdev->device, NULL); 54 if (unlikely(!func)) 55 return NULL; 56 57 if (func->devfn == pdev->devfn) { 58 func = pci_get_device(pdev->vendor, pdev->device, func); 59 if (unlikely(!func)) 60 return NULL; 61 } 62 63 if (func->devfn != PCI_DEV_FN_HOST_DEVICE && 64 func->devfn != PCI_DEV_FN_OTG) { 65 return NULL; 66 } 67 68 return func; 69 } 70 71 static int cdns3_pci_probe(struct pci_dev *pdev, 72 const struct pci_device_id *id) 73 { 74 struct platform_device_info plat_info; 75 struct cdns3_wrap *wrap; 76 struct resource *res; 77 struct pci_dev *func; 78 int err; 79 80 /* 81 * for GADGET/HOST PCI (devfn) function number is 0, 82 * for OTG PCI (devfn) function number is 1 83 */ 84 if (!id || (pdev->devfn != PCI_DEV_FN_HOST_DEVICE && 85 pdev->devfn != PCI_DEV_FN_OTG)) 86 return -EINVAL; 87 88 func = cdns3_get_second_fun(pdev); 89 if (unlikely(!func)) 90 return -EINVAL; 91 92 err = pcim_enable_device(pdev); 93 if (err) { 94 dev_err(&pdev->dev, "Enabling PCI device has failed %d\n", err); 95 return err; 96 } 97 98 pci_set_master(pdev); 99 100 if (pci_is_enabled(func)) { 101 wrap = pci_get_drvdata(func); 102 } else { 103 wrap = kzalloc(sizeof(*wrap), GFP_KERNEL); 104 if (!wrap) { 105 pci_disable_device(pdev); 106 return -ENOMEM; 107 } 108 } 109 110 res = wrap->dev_res; 111 112 if (pdev->devfn == PCI_DEV_FN_HOST_DEVICE) { 113 /* function 0: host(BAR_0) + device(BAR_1).*/ 114 dev_dbg(&pdev->dev, "Initialize Device resources\n"); 115 res[RES_DEV_ID].start = pci_resource_start(pdev, PCI_BAR_DEV); 116 res[RES_DEV_ID].end = pci_resource_end(pdev, PCI_BAR_DEV); 117 res[RES_DEV_ID].name = "dev"; 118 res[RES_DEV_ID].flags = IORESOURCE_MEM; 119 dev_dbg(&pdev->dev, "USBSS-DEV physical base addr: %pa\n", 120 &res[RES_DEV_ID].start); 121 122 res[RES_HOST_ID].start = pci_resource_start(pdev, PCI_BAR_HOST); 123 res[RES_HOST_ID].end = pci_resource_end(pdev, PCI_BAR_HOST); 124 res[RES_HOST_ID].name = "xhci"; 125 res[RES_HOST_ID].flags = IORESOURCE_MEM; 126 dev_dbg(&pdev->dev, "USBSS-XHCI physical base addr: %pa\n", 127 &res[RES_HOST_ID].start); 128 129 /* Interrupt for XHCI */ 130 wrap->dev_res[RES_IRQ_HOST_ID].start = pdev->irq; 131 wrap->dev_res[RES_IRQ_HOST_ID].name = "host"; 132 wrap->dev_res[RES_IRQ_HOST_ID].flags = IORESOURCE_IRQ; 133 134 /* Interrupt device. It's the same as for HOST. */ 135 wrap->dev_res[RES_IRQ_PERIPHERAL_ID].start = pdev->irq; 136 wrap->dev_res[RES_IRQ_PERIPHERAL_ID].name = "peripheral"; 137 wrap->dev_res[RES_IRQ_PERIPHERAL_ID].flags = IORESOURCE_IRQ; 138 } else { 139 res[RES_DRD_ID].start = pci_resource_start(pdev, PCI_BAR_OTG); 140 res[RES_DRD_ID].end = pci_resource_end(pdev, PCI_BAR_OTG); 141 res[RES_DRD_ID].name = "otg"; 142 res[RES_DRD_ID].flags = IORESOURCE_MEM; 143 dev_dbg(&pdev->dev, "USBSS-DRD physical base addr: %pa\n", 144 &res[RES_DRD_ID].start); 145 146 /* Interrupt for OTG/DRD. */ 147 wrap->dev_res[RES_IRQ_OTG_ID].start = pdev->irq; 148 wrap->dev_res[RES_IRQ_OTG_ID].name = "otg"; 149 wrap->dev_res[RES_IRQ_OTG_ID].flags = IORESOURCE_IRQ; 150 } 151 152 if (pci_is_enabled(func)) { 153 /* set up platform device info */ 154 memset(&plat_info, 0, sizeof(plat_info)); 155 plat_info.parent = &pdev->dev; 156 plat_info.fwnode = pdev->dev.fwnode; 157 plat_info.name = PLAT_DRIVER_NAME; 158 plat_info.id = pdev->devfn; 159 wrap->devfn = pdev->devfn; 160 plat_info.res = wrap->dev_res; 161 plat_info.num_res = ARRAY_SIZE(wrap->dev_res); 162 plat_info.dma_mask = pdev->dma_mask; 163 /* register platform device */ 164 wrap->plat_dev = platform_device_register_full(&plat_info); 165 if (IS_ERR(wrap->plat_dev)) { 166 pci_disable_device(pdev); 167 err = PTR_ERR(wrap->plat_dev); 168 kfree(wrap); 169 return err; 170 } 171 } 172 173 pci_set_drvdata(pdev, wrap); 174 return err; 175 } 176 177 static void cdns3_pci_remove(struct pci_dev *pdev) 178 { 179 struct cdns3_wrap *wrap; 180 struct pci_dev *func; 181 182 func = cdns3_get_second_fun(pdev); 183 184 wrap = (struct cdns3_wrap *)pci_get_drvdata(pdev); 185 if (wrap->devfn == pdev->devfn) 186 platform_device_unregister(wrap->plat_dev); 187 188 if (!pci_is_enabled(func)) 189 kfree(wrap); 190 } 191 192 static const struct pci_device_id cdns3_pci_ids[] = { 193 { PCI_DEVICE(CDNS_VENDOR_ID, CDNS_DEVICE_ID), }, 194 { 0, } 195 }; 196 197 static struct pci_driver cdns3_pci_driver = { 198 .name = PCI_DRIVER_NAME, 199 .id_table = cdns3_pci_ids, 200 .probe = cdns3_pci_probe, 201 .remove = cdns3_pci_remove, 202 }; 203 204 module_pci_driver(cdns3_pci_driver); 205 MODULE_DEVICE_TABLE(pci, cdns3_pci_ids); 206 207 MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>"); 208 MODULE_LICENSE("GPL v2"); 209 MODULE_DESCRIPTION("Cadence USBSS PCI wrapper"); 210