Commit | Line | Data |
---|---|---|
5a3aa2a8 JP |
1 | /* |
2 | * PCIe RC driver for Synopsys DesignWare Core | |
3 | * | |
4 | * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) | |
5 | * | |
6 | * Authors: Joao Pinto <jpinto@synopsys.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | */ | |
12 | #include <linux/clk.h> | |
13 | #include <linux/delay.h> | |
14 | #include <linux/gpio.h> | |
15 | #include <linux/interrupt.h> | |
16 | #include <linux/kernel.h> | |
17 | #include <linux/module.h> | |
18 | #include <linux/of_gpio.h> | |
19 | #include <linux/pci.h> | |
20 | #include <linux/platform_device.h> | |
21 | #include <linux/resource.h> | |
22 | #include <linux/signal.h> | |
23 | #include <linux/types.h> | |
24 | ||
25 | #include "pcie-designware.h" | |
26 | ||
27 | struct dw_plat_pcie { | |
28 | void __iomem *mem_base; | |
29 | struct pcie_port pp; | |
30 | }; | |
31 | ||
32 | static irqreturn_t dw_plat_pcie_msi_irq_handler(int irq, void *arg) | |
33 | { | |
34 | struct pcie_port *pp = arg; | |
35 | ||
36 | return dw_handle_msi_irq(pp); | |
37 | } | |
38 | ||
39 | static void dw_plat_pcie_host_init(struct pcie_port *pp) | |
40 | { | |
41 | dw_pcie_setup_rc(pp); | |
42 | dw_pcie_wait_for_link(pp); | |
43 | ||
44 | if (IS_ENABLED(CONFIG_PCI_MSI)) | |
45 | dw_pcie_msi_init(pp); | |
46 | } | |
47 | ||
48 | static struct pcie_host_ops dw_plat_pcie_host_ops = { | |
49 | .host_init = dw_plat_pcie_host_init, | |
50 | }; | |
51 | ||
52 | static int dw_plat_add_pcie_port(struct pcie_port *pp, | |
53 | struct platform_device *pdev) | |
54 | { | |
55 | int ret; | |
56 | ||
57 | pp->irq = platform_get_irq(pdev, 1); | |
58 | if (pp->irq < 0) | |
59 | return pp->irq; | |
60 | ||
61 | if (IS_ENABLED(CONFIG_PCI_MSI)) { | |
62 | pp->msi_irq = platform_get_irq(pdev, 0); | |
63 | if (pp->msi_irq < 0) | |
64 | return pp->msi_irq; | |
65 | ||
66 | ret = devm_request_irq(&pdev->dev, pp->msi_irq, | |
67 | dw_plat_pcie_msi_irq_handler, | |
68 | IRQF_SHARED, "dw-plat-pcie-msi", pp); | |
69 | if (ret) { | |
70 | dev_err(&pdev->dev, "failed to request MSI IRQ\n"); | |
71 | return ret; | |
72 | } | |
73 | } | |
74 | ||
75 | pp->root_bus_nr = -1; | |
76 | pp->ops = &dw_plat_pcie_host_ops; | |
77 | ||
78 | ret = dw_pcie_host_init(pp); | |
79 | if (ret) { | |
80 | dev_err(&pdev->dev, "failed to initialize host\n"); | |
81 | return ret; | |
82 | } | |
83 | ||
84 | return 0; | |
85 | } | |
86 | ||
87 | static int dw_plat_pcie_probe(struct platform_device *pdev) | |
88 | { | |
89 | struct dw_plat_pcie *dw_plat_pcie; | |
90 | struct pcie_port *pp; | |
91 | struct resource *res; /* Resource from DT */ | |
92 | int ret; | |
93 | ||
94 | dw_plat_pcie = devm_kzalloc(&pdev->dev, sizeof(*dw_plat_pcie), | |
95 | GFP_KERNEL); | |
96 | if (!dw_plat_pcie) | |
97 | return -ENOMEM; | |
98 | ||
99 | pp = &dw_plat_pcie->pp; | |
100 | pp->dev = &pdev->dev; | |
101 | ||
102 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
103 | if (!res) | |
104 | return -ENODEV; | |
105 | ||
106 | dw_plat_pcie->mem_base = devm_ioremap_resource(&pdev->dev, res); | |
107 | if (IS_ERR(dw_plat_pcie->mem_base)) | |
108 | return PTR_ERR(dw_plat_pcie->mem_base); | |
109 | ||
110 | pp->dbi_base = dw_plat_pcie->mem_base; | |
111 | ||
112 | ret = dw_plat_add_pcie_port(pp, pdev); | |
113 | if (ret < 0) | |
114 | return ret; | |
115 | ||
116 | platform_set_drvdata(pdev, dw_plat_pcie); | |
117 | return 0; | |
118 | } | |
119 | ||
120 | static const struct of_device_id dw_plat_pcie_of_match[] = { | |
121 | { .compatible = "snps,dw-pcie", }, | |
122 | {}, | |
123 | }; | |
124 | MODULE_DEVICE_TABLE(of, dw_plat_pcie_of_match); | |
125 | ||
126 | static struct platform_driver dw_plat_pcie_driver = { | |
127 | .driver = { | |
128 | .name = "dw-pcie", | |
129 | .of_match_table = dw_plat_pcie_of_match, | |
130 | }, | |
131 | .probe = dw_plat_pcie_probe, | |
132 | }; | |
133 | ||
134 | module_platform_driver(dw_plat_pcie_driver); | |
135 | ||
136 | MODULE_AUTHOR("Joao Pinto <Joao.Pinto@synopsys.com>"); | |
137 | MODULE_DESCRIPTION("Synopsys PCIe host controller glue platform driver"); | |
138 | MODULE_LICENSE("GPL v2"); |