1 // SPDX-License-Identifier: GPL-2.0
3 * Cadence USBSS PCI Glue driver
5 * Copyright (C) 2018-2019 Cadence.
7 * Author: Pawel Laszczak <pawell@cadence.com>
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>
18 struct platform_device
*plat_dev
;
19 struct resource dev_res
[6];
23 #define RES_IRQ_HOST_ID 0
24 #define RES_IRQ_PERIPHERAL_ID 1
25 #define RES_IRQ_OTG_ID 2
30 #define PCI_BAR_HOST 0
34 #define PCI_DEV_FN_HOST_DEVICE 0
35 #define PCI_DEV_FN_OTG 1
37 #define PCI_DRIVER_NAME "cdns3-pci-usbss"
38 #define PLAT_DRIVER_NAME "cdns-usb3"
40 static struct pci_dev
*cdns3_get_second_fun(struct pci_dev
*pdev
)
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.
50 func
= pci_get_device(pdev
->vendor
, pdev
->device
, NULL
);
54 if (func
->devfn
== pdev
->devfn
) {
55 func
= pci_get_device(pdev
->vendor
, pdev
->device
, func
);
60 if (func
->devfn
!= PCI_DEV_FN_HOST_DEVICE
&&
61 func
->devfn
!= PCI_DEV_FN_OTG
) {
68 static int cdns3_pci_probe(struct pci_dev
*pdev
,
69 const struct pci_device_id
*id
)
71 struct platform_device_info plat_info
;
72 struct cdns3_wrap
*wrap
;
78 * for GADGET/HOST PCI (devfn) function number is 0,
79 * for OTG PCI (devfn) function number is 1
81 if (!id
|| (pdev
->devfn
!= PCI_DEV_FN_HOST_DEVICE
&&
82 pdev
->devfn
!= PCI_DEV_FN_OTG
))
85 func
= cdns3_get_second_fun(pdev
);
89 err
= pcim_enable_device(pdev
);
91 dev_err(&pdev
->dev
, "Enabling PCI device has failed %d\n", err
);
97 if (pci_is_enabled(func
)) {
98 wrap
= pci_get_drvdata(func
);
100 wrap
= kzalloc(sizeof(*wrap
), GFP_KERNEL
);
102 pci_disable_device(pdev
);
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
);
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
);
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
;
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
;
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
);
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
;
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
);
170 pci_set_drvdata(pdev
, wrap
);
174 static void cdns3_pci_remove(struct pci_dev
*pdev
)
176 struct cdns3_wrap
*wrap
;
177 struct pci_dev
*func
;
179 func
= cdns3_get_second_fun(pdev
);
181 wrap
= (struct cdns3_wrap
*)pci_get_drvdata(pdev
);
182 if (wrap
->devfn
== pdev
->devfn
)
183 platform_device_unregister(wrap
->plat_dev
);
185 if (!pci_is_enabled(func
))
189 static const struct pci_device_id cdns3_pci_ids
[] = {
190 { PCI_VDEVICE(CDNS
, PCI_DEVICE_ID_CDNS_USBSS
) },
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
,
201 module_pci_driver(cdns3_pci_driver
);
202 MODULE_DEVICE_TABLE(pci
, cdns3_pci_ids
);
204 MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
205 MODULE_LICENSE("GPL v2");
206 MODULE_DESCRIPTION("Cadence USBSS PCI wrapper");