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>
16 #include <linux/pci.h>
17 #include <linux/platform_device.h>
18 #include <linux/resource.h>
19 #include <linux/types.h>
21 #include "pcie-designware.h"
25 enum dw_pcie_device_mode mode
;
28 struct dw_plat_pcie_of_data
{
29 enum dw_pcie_device_mode mode
;
32 static const struct dw_pcie_host_ops dw_plat_pcie_host_ops
= {
35 static void dw_plat_pcie_ep_init(struct dw_pcie_ep
*ep
)
37 struct dw_pcie
*pci
= to_dw_pcie_from_ep(ep
);
40 for (bar
= 0; bar
< PCI_STD_NUM_BARS
; bar
++)
41 dw_pcie_ep_reset_bar(pci
, bar
);
44 static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep
*ep
, u8 func_no
,
45 unsigned int type
, u16 interrupt_num
)
47 struct dw_pcie
*pci
= to_dw_pcie_from_ep(ep
);
51 return dw_pcie_ep_raise_intx_irq(ep
, func_no
);
53 return dw_pcie_ep_raise_msi_irq(ep
, func_no
, interrupt_num
);
55 return dw_pcie_ep_raise_msix_irq(ep
, func_no
, interrupt_num
);
57 dev_err(pci
->dev
, "UNKNOWN IRQ type\n");
63 static const struct pci_epc_features dw_plat_pcie_epc_features
= {
64 .linkup_notifier
= false,
69 static const struct pci_epc_features
*
70 dw_plat_pcie_get_features(struct dw_pcie_ep
*ep
)
72 return &dw_plat_pcie_epc_features
;
75 static const struct dw_pcie_ep_ops pcie_ep_ops
= {
76 .init
= dw_plat_pcie_ep_init
,
77 .raise_irq
= dw_plat_pcie_ep_raise_irq
,
78 .get_features
= dw_plat_pcie_get_features
,
81 static int dw_plat_add_pcie_port(struct dw_plat_pcie
*dw_plat_pcie
,
82 struct platform_device
*pdev
)
84 struct dw_pcie
*pci
= dw_plat_pcie
->pci
;
85 struct dw_pcie_rp
*pp
= &pci
->pp
;
86 struct device
*dev
= &pdev
->dev
;
89 pp
->irq
= platform_get_irq(pdev
, 1);
93 pp
->num_vectors
= MAX_MSI_IRQS
;
94 pp
->ops
= &dw_plat_pcie_host_ops
;
96 ret
= dw_pcie_host_init(pp
);
98 dev_err(dev
, "Failed to initialize host\n");
105 static int dw_plat_pcie_probe(struct platform_device
*pdev
)
107 struct device
*dev
= &pdev
->dev
;
108 struct dw_plat_pcie
*dw_plat_pcie
;
111 const struct dw_plat_pcie_of_data
*data
;
112 enum dw_pcie_device_mode mode
;
114 data
= of_device_get_match_data(dev
);
118 mode
= (enum dw_pcie_device_mode
)data
->mode
;
120 dw_plat_pcie
= devm_kzalloc(dev
, sizeof(*dw_plat_pcie
), GFP_KERNEL
);
124 pci
= devm_kzalloc(dev
, sizeof(*pci
), GFP_KERNEL
);
130 dw_plat_pcie
->pci
= pci
;
131 dw_plat_pcie
->mode
= mode
;
133 platform_set_drvdata(pdev
, dw_plat_pcie
);
135 switch (dw_plat_pcie
->mode
) {
136 case DW_PCIE_RC_TYPE
:
137 if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_HOST
))
140 ret
= dw_plat_add_pcie_port(dw_plat_pcie
, pdev
);
142 case DW_PCIE_EP_TYPE
:
143 if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP
))
146 pci
->ep
.ops
= &pcie_ep_ops
;
147 ret
= dw_pcie_ep_init(&pci
->ep
);
151 ret
= dw_pcie_ep_init_registers(&pci
->ep
);
153 dev_err(dev
, "Failed to initialize DWC endpoint registers\n");
154 dw_pcie_ep_deinit(&pci
->ep
);
157 pci_epc_init_notify(pci
->ep
.epc
);
161 dev_err(dev
, "INVALID device type %d\n", dw_plat_pcie
->mode
);
169 static const struct dw_plat_pcie_of_data dw_plat_pcie_rc_of_data
= {
170 .mode
= DW_PCIE_RC_TYPE
,
173 static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data
= {
174 .mode
= DW_PCIE_EP_TYPE
,
177 static const struct of_device_id dw_plat_pcie_of_match
[] = {
179 .compatible
= "snps,dw-pcie",
180 .data
= &dw_plat_pcie_rc_of_data
,
183 .compatible
= "snps,dw-pcie-ep",
184 .data
= &dw_plat_pcie_ep_of_data
,
189 static struct platform_driver dw_plat_pcie_driver
= {
192 .of_match_table
= dw_plat_pcie_of_match
,
193 .suppress_bind_attrs
= true,
195 .probe
= dw_plat_pcie_probe
,
197 builtin_platform_driver(dw_plat_pcie_driver
);