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