1 // SPDX-License-Identifier: GPL-2.0
3 * PCIe RC driver for Synopsys DesignWare Core
5 * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
7 * Authors: Joao Pinto <Joao.Pinto@synopsys.com>
10 #include <linux/delay.h>
11 #include <linux/gpio.h>
12 #include <linux/interrupt.h>
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/of_device.h>
16 #include <linux/pci.h>
17 #include <linux/platform_device.h>
18 #include <linux/resource.h>
19 #include <linux/types.h>
20 #include <linux/regmap.h>
22 #include "pcie-designware.h"
26 struct regmap
*regmap
;
27 enum dw_pcie_device_mode mode
;
30 struct dw_plat_pcie_of_data
{
31 enum dw_pcie_device_mode mode
;
34 static const struct of_device_id dw_plat_pcie_of_match
[];
36 static int dw_plat_pcie_host_init(struct pcie_port
*pp
)
38 struct dw_pcie
*pci
= to_dw_pcie_from_pp(pp
);
41 dw_pcie_wait_for_link(pci
);
43 if (IS_ENABLED(CONFIG_PCI_MSI
))
49 static void dw_plat_set_num_vectors(struct pcie_port
*pp
)
51 pp
->num_vectors
= MAX_MSI_IRQS
;
54 static const struct dw_pcie_host_ops dw_plat_pcie_host_ops
= {
55 .host_init
= dw_plat_pcie_host_init
,
56 .set_num_vectors
= dw_plat_set_num_vectors
,
59 static int dw_plat_pcie_establish_link(struct dw_pcie
*pci
)
64 static const struct dw_pcie_ops dw_pcie_ops
= {
65 .start_link
= dw_plat_pcie_establish_link
,
68 static void dw_plat_pcie_ep_init(struct dw_pcie_ep
*ep
)
70 struct dw_pcie
*pci
= to_dw_pcie_from_ep(ep
);
73 for (bar
= BAR_0
; bar
<= BAR_5
; bar
++)
74 dw_pcie_ep_reset_bar(pci
, bar
);
77 static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep
*ep
, u8 func_no
,
78 enum pci_epc_irq_type type
,
81 struct dw_pcie
*pci
= to_dw_pcie_from_ep(ep
);
84 case PCI_EPC_IRQ_LEGACY
:
85 return dw_pcie_ep_raise_legacy_irq(ep
, func_no
);
87 return dw_pcie_ep_raise_msi_irq(ep
, func_no
, interrupt_num
);
88 case PCI_EPC_IRQ_MSIX
:
89 return dw_pcie_ep_raise_msix_irq(ep
, func_no
, interrupt_num
);
91 dev_err(pci
->dev
, "UNKNOWN IRQ type\n");
97 static const struct pci_epc_features dw_plat_pcie_epc_features
= {
98 .linkup_notifier
= false,
100 .msix_capable
= true,
103 static const struct pci_epc_features
*
104 dw_plat_pcie_get_features(struct dw_pcie_ep
*ep
)
106 return &dw_plat_pcie_epc_features
;
109 static struct dw_pcie_ep_ops pcie_ep_ops
= {
110 .ep_init
= dw_plat_pcie_ep_init
,
111 .raise_irq
= dw_plat_pcie_ep_raise_irq
,
112 .get_features
= dw_plat_pcie_get_features
,
115 static int dw_plat_add_pcie_port(struct dw_plat_pcie
*dw_plat_pcie
,
116 struct platform_device
*pdev
)
118 struct dw_pcie
*pci
= dw_plat_pcie
->pci
;
119 struct pcie_port
*pp
= &pci
->pp
;
120 struct device
*dev
= &pdev
->dev
;
123 pp
->irq
= platform_get_irq(pdev
, 1);
127 if (IS_ENABLED(CONFIG_PCI_MSI
)) {
128 pp
->msi_irq
= platform_get_irq(pdev
, 0);
133 pp
->ops
= &dw_plat_pcie_host_ops
;
135 ret
= dw_pcie_host_init(pp
);
137 dev_err(dev
, "Failed to initialize host\n");
144 static int dw_plat_add_pcie_ep(struct dw_plat_pcie
*dw_plat_pcie
,
145 struct platform_device
*pdev
)
148 struct dw_pcie_ep
*ep
;
149 struct resource
*res
;
150 struct device
*dev
= &pdev
->dev
;
151 struct dw_pcie
*pci
= dw_plat_pcie
->pci
;
154 ep
->ops
= &pcie_ep_ops
;
156 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "dbi2");
157 pci
->dbi_base2
= devm_ioremap_resource(dev
, res
);
158 if (IS_ERR(pci
->dbi_base2
))
159 return PTR_ERR(pci
->dbi_base2
);
161 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "addr_space");
165 ep
->phys_base
= res
->start
;
166 ep
->addr_size
= resource_size(res
);
168 ret
= dw_pcie_ep_init(ep
);
170 dev_err(dev
, "Failed to initialize endpoint\n");
176 static int dw_plat_pcie_probe(struct platform_device
*pdev
)
178 struct device
*dev
= &pdev
->dev
;
179 struct dw_plat_pcie
*dw_plat_pcie
;
181 struct resource
*res
; /* Resource from DT */
183 const struct of_device_id
*match
;
184 const struct dw_plat_pcie_of_data
*data
;
185 enum dw_pcie_device_mode mode
;
187 match
= of_match_device(dw_plat_pcie_of_match
, dev
);
191 data
= (struct dw_plat_pcie_of_data
*)match
->data
;
192 mode
= (enum dw_pcie_device_mode
)data
->mode
;
194 dw_plat_pcie
= devm_kzalloc(dev
, sizeof(*dw_plat_pcie
), GFP_KERNEL
);
198 pci
= devm_kzalloc(dev
, sizeof(*pci
), GFP_KERNEL
);
203 pci
->ops
= &dw_pcie_ops
;
205 dw_plat_pcie
->pci
= pci
;
206 dw_plat_pcie
->mode
= mode
;
208 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "dbi");
210 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
212 pci
->dbi_base
= devm_ioremap_resource(dev
, res
);
213 if (IS_ERR(pci
->dbi_base
))
214 return PTR_ERR(pci
->dbi_base
);
216 platform_set_drvdata(pdev
, dw_plat_pcie
);
218 switch (dw_plat_pcie
->mode
) {
219 case DW_PCIE_RC_TYPE
:
220 if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_HOST
))
223 ret
= dw_plat_add_pcie_port(dw_plat_pcie
, pdev
);
227 case DW_PCIE_EP_TYPE
:
228 if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP
))
231 ret
= dw_plat_add_pcie_ep(dw_plat_pcie
, pdev
);
236 dev_err(dev
, "INVALID device type %d\n", dw_plat_pcie
->mode
);
242 static const struct dw_plat_pcie_of_data dw_plat_pcie_rc_of_data
= {
243 .mode
= DW_PCIE_RC_TYPE
,
246 static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data
= {
247 .mode
= DW_PCIE_EP_TYPE
,
250 static const struct of_device_id dw_plat_pcie_of_match
[] = {
252 .compatible
= "snps,dw-pcie",
253 .data
= &dw_plat_pcie_rc_of_data
,
256 .compatible
= "snps,dw-pcie-ep",
257 .data
= &dw_plat_pcie_ep_of_data
,
262 static struct platform_driver dw_plat_pcie_driver
= {
265 .of_match_table
= dw_plat_pcie_of_match
,
266 .suppress_bind_attrs
= true,
268 .probe
= dw_plat_pcie_probe
,
270 builtin_platform_driver(dw_plat_pcie_driver
);