Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Cadence USBSS PCI Glue driver
0004  *
0005  * Copyright (C) 2018-2019 Cadence.
0006  *
0007  * Author: Pawel Laszczak <pawell@cadence.com>
0008  */
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/pci.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/dma-mapping.h>
0015 #include <linux/slab.h>
0016 
0017 struct cdns3_wrap {
0018     struct platform_device *plat_dev;
0019     struct resource dev_res[6];
0020     int devfn;
0021 };
0022 
0023 #define RES_IRQ_HOST_ID     0
0024 #define RES_IRQ_PERIPHERAL_ID   1
0025 #define RES_IRQ_OTG_ID      2
0026 #define RES_HOST_ID     3
0027 #define RES_DEV_ID      4
0028 #define RES_DRD_ID      5
0029 
0030 #define PCI_BAR_HOST        0
0031 #define PCI_BAR_DEV     2
0032 #define PCI_BAR_OTG     0
0033 
0034 #define PCI_DEV_FN_HOST_DEVICE  0
0035 #define PCI_DEV_FN_OTG      1
0036 
0037 #define PCI_DRIVER_NAME     "cdns3-pci-usbss"
0038 #define PLAT_DRIVER_NAME    "cdns-usb3"
0039 
0040 #define CDNS_VENDOR_ID      0x17cd
0041 #define CDNS_DEVICE_ID      0x0100
0042 
0043 static struct pci_dev *cdns3_get_second_fun(struct pci_dev *pdev)
0044 {
0045     struct pci_dev *func;
0046 
0047     /*
0048      * Gets the second function.
0049      * It's little tricky, but this platform has two function.
0050      * The fist keeps resources for Host/Device while the second
0051      * keeps resources for DRD/OTG.
0052      */
0053     func = pci_get_device(pdev->vendor, pdev->device, NULL);
0054     if (unlikely(!func))
0055         return NULL;
0056 
0057     if (func->devfn == pdev->devfn) {
0058         func = pci_get_device(pdev->vendor, pdev->device, func);
0059         if (unlikely(!func))
0060             return NULL;
0061     }
0062 
0063     return func;
0064 }
0065 
0066 static int cdns3_pci_probe(struct pci_dev *pdev,
0067                const struct pci_device_id *id)
0068 {
0069     struct platform_device_info plat_info;
0070     struct cdns3_wrap *wrap;
0071     struct resource *res;
0072     struct pci_dev *func;
0073     int err;
0074 
0075     /*
0076      * for GADGET/HOST PCI (devfn) function number is 0,
0077      * for OTG PCI (devfn) function number is 1
0078      */
0079     if (!id || (pdev->devfn != PCI_DEV_FN_HOST_DEVICE &&
0080             pdev->devfn != PCI_DEV_FN_OTG))
0081         return -EINVAL;
0082 
0083     func = cdns3_get_second_fun(pdev);
0084     if (unlikely(!func))
0085         return -EINVAL;
0086 
0087     err = pcim_enable_device(pdev);
0088     if (err) {
0089         dev_err(&pdev->dev, "Enabling PCI device has failed %d\n", err);
0090         return err;
0091     }
0092 
0093     pci_set_master(pdev);
0094 
0095     if (pci_is_enabled(func)) {
0096         wrap = pci_get_drvdata(func);
0097     } else {
0098         wrap = kzalloc(sizeof(*wrap), GFP_KERNEL);
0099         if (!wrap) {
0100             pci_disable_device(pdev);
0101             return -ENOMEM;
0102         }
0103     }
0104 
0105     res = wrap->dev_res;
0106 
0107     if (pdev->devfn == PCI_DEV_FN_HOST_DEVICE) {
0108         /* function 0: host(BAR_0) + device(BAR_1).*/
0109         dev_dbg(&pdev->dev, "Initialize Device resources\n");
0110         res[RES_DEV_ID].start = pci_resource_start(pdev, PCI_BAR_DEV);
0111         res[RES_DEV_ID].end =   pci_resource_end(pdev, PCI_BAR_DEV);
0112         res[RES_DEV_ID].name = "dev";
0113         res[RES_DEV_ID].flags = IORESOURCE_MEM;
0114         dev_dbg(&pdev->dev, "USBSS-DEV physical base addr: %pa\n",
0115             &res[RES_DEV_ID].start);
0116 
0117         res[RES_HOST_ID].start = pci_resource_start(pdev, PCI_BAR_HOST);
0118         res[RES_HOST_ID].end = pci_resource_end(pdev, PCI_BAR_HOST);
0119         res[RES_HOST_ID].name = "xhci";
0120         res[RES_HOST_ID].flags = IORESOURCE_MEM;
0121         dev_dbg(&pdev->dev, "USBSS-XHCI physical base addr: %pa\n",
0122             &res[RES_HOST_ID].start);
0123 
0124         /* Interrupt for XHCI */
0125         wrap->dev_res[RES_IRQ_HOST_ID].start = pdev->irq;
0126         wrap->dev_res[RES_IRQ_HOST_ID].name = "host";
0127         wrap->dev_res[RES_IRQ_HOST_ID].flags = IORESOURCE_IRQ;
0128 
0129         /* Interrupt device. It's the same as for HOST. */
0130         wrap->dev_res[RES_IRQ_PERIPHERAL_ID].start = pdev->irq;
0131         wrap->dev_res[RES_IRQ_PERIPHERAL_ID].name = "peripheral";
0132         wrap->dev_res[RES_IRQ_PERIPHERAL_ID].flags = IORESOURCE_IRQ;
0133     } else {
0134         res[RES_DRD_ID].start = pci_resource_start(pdev, PCI_BAR_OTG);
0135         res[RES_DRD_ID].end =   pci_resource_end(pdev, PCI_BAR_OTG);
0136         res[RES_DRD_ID].name = "otg";
0137         res[RES_DRD_ID].flags = IORESOURCE_MEM;
0138         dev_dbg(&pdev->dev, "USBSS-DRD physical base addr: %pa\n",
0139             &res[RES_DRD_ID].start);
0140 
0141         /* Interrupt for OTG/DRD. */
0142         wrap->dev_res[RES_IRQ_OTG_ID].start = pdev->irq;
0143         wrap->dev_res[RES_IRQ_OTG_ID].name = "otg";
0144         wrap->dev_res[RES_IRQ_OTG_ID].flags = IORESOURCE_IRQ;
0145     }
0146 
0147     if (pci_is_enabled(func)) {
0148         /* set up platform device info */
0149         memset(&plat_info, 0, sizeof(plat_info));
0150         plat_info.parent = &pdev->dev;
0151         plat_info.fwnode = pdev->dev.fwnode;
0152         plat_info.name = PLAT_DRIVER_NAME;
0153         plat_info.id = pdev->devfn;
0154         wrap->devfn  = pdev->devfn;
0155         plat_info.res = wrap->dev_res;
0156         plat_info.num_res = ARRAY_SIZE(wrap->dev_res);
0157         plat_info.dma_mask = pdev->dma_mask;
0158         /* register platform device */
0159         wrap->plat_dev = platform_device_register_full(&plat_info);
0160         if (IS_ERR(wrap->plat_dev)) {
0161             pci_disable_device(pdev);
0162             err = PTR_ERR(wrap->plat_dev);
0163             kfree(wrap);
0164             return err;
0165         }
0166     }
0167 
0168     pci_set_drvdata(pdev, wrap);
0169     return err;
0170 }
0171 
0172 static void cdns3_pci_remove(struct pci_dev *pdev)
0173 {
0174     struct cdns3_wrap *wrap;
0175     struct pci_dev *func;
0176 
0177     func = cdns3_get_second_fun(pdev);
0178 
0179     wrap = (struct cdns3_wrap *)pci_get_drvdata(pdev);
0180     if (wrap->devfn == pdev->devfn)
0181         platform_device_unregister(wrap->plat_dev);
0182 
0183     if (!pci_is_enabled(func))
0184         kfree(wrap);
0185 }
0186 
0187 static const struct pci_device_id cdns3_pci_ids[] = {
0188     { PCI_DEVICE(CDNS_VENDOR_ID, CDNS_DEVICE_ID), },
0189     { 0, }
0190 };
0191 
0192 static struct pci_driver cdns3_pci_driver = {
0193     .name = PCI_DRIVER_NAME,
0194     .id_table = cdns3_pci_ids,
0195     .probe = cdns3_pci_probe,
0196     .remove = cdns3_pci_remove,
0197 };
0198 
0199 module_pci_driver(cdns3_pci_driver);
0200 MODULE_DEVICE_TABLE(pci, cdns3_pci_ids);
0201 
0202 MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
0203 MODULE_LICENSE("GPL v2");
0204 MODULE_DESCRIPTION("Cadence USBSS PCI wrapper");