blob: 537f58a664fa230d3f6496ff68f4e7495d0f5952 [file] [log] [blame]
Joao Pinto5a3aa2a2016-03-10 14:44:52 -06001/*
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>
Paul Gortmakerca8d3342016-07-02 19:13:23 -040017#include <linux/init.h>
Joao Pinto5a3aa2a2016-03-10 14:44:52 -060018#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
27struct dw_plat_pcie {
Bjorn Helgaasbb8a7942016-10-06 13:32:15 -050028 struct pcie_port pp; /* pp.dbi_base is DT 0th resource */
Joao Pinto5a3aa2a2016-03-10 14:44:52 -060029};
30
31static irqreturn_t dw_plat_pcie_msi_irq_handler(int irq, void *arg)
32{
33 struct pcie_port *pp = arg;
34
35 return dw_handle_msi_irq(pp);
36}
37
38static void dw_plat_pcie_host_init(struct pcie_port *pp)
39{
40 dw_pcie_setup_rc(pp);
41 dw_pcie_wait_for_link(pp);
42
43 if (IS_ENABLED(CONFIG_PCI_MSI))
44 dw_pcie_msi_init(pp);
45}
46
47static struct pcie_host_ops dw_plat_pcie_host_ops = {
48 .host_init = dw_plat_pcie_host_init,
49};
50
51static int dw_plat_add_pcie_port(struct pcie_port *pp,
52 struct platform_device *pdev)
53{
Bjorn Helgaas2d6054b2016-10-06 13:32:15 -050054 struct device *dev = pp->dev;
Joao Pinto5a3aa2a2016-03-10 14:44:52 -060055 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
Bjorn Helgaas2d6054b2016-10-06 13:32:15 -050066 ret = devm_request_irq(dev, pp->msi_irq,
Joao Pinto5a3aa2a2016-03-10 14:44:52 -060067 dw_plat_pcie_msi_irq_handler,
68 IRQF_SHARED, "dw-plat-pcie-msi", pp);
69 if (ret) {
Bjorn Helgaas2d6054b2016-10-06 13:32:15 -050070 dev_err(dev, "failed to request MSI IRQ\n");
Joao Pinto5a3aa2a2016-03-10 14:44:52 -060071 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) {
Bjorn Helgaas2d6054b2016-10-06 13:32:15 -050080 dev_err(dev, "failed to initialize host\n");
Joao Pinto5a3aa2a2016-03-10 14:44:52 -060081 return ret;
82 }
83
84 return 0;
85}
86
87static int dw_plat_pcie_probe(struct platform_device *pdev)
88{
Bjorn Helgaas2d6054b2016-10-06 13:32:15 -050089 struct device *dev = &pdev->dev;
Joao Pinto5a3aa2a2016-03-10 14:44:52 -060090 struct dw_plat_pcie *dw_plat_pcie;
91 struct pcie_port *pp;
92 struct resource *res; /* Resource from DT */
93 int ret;
94
Bjorn Helgaas2d6054b2016-10-06 13:32:15 -050095 dw_plat_pcie = devm_kzalloc(dev, sizeof(*dw_plat_pcie), GFP_KERNEL);
Joao Pinto5a3aa2a2016-03-10 14:44:52 -060096 if (!dw_plat_pcie)
97 return -ENOMEM;
98
99 pp = &dw_plat_pcie->pp;
Bjorn Helgaas2d6054b2016-10-06 13:32:15 -0500100 pp->dev = dev;
Joao Pinto5a3aa2a2016-03-10 14:44:52 -0600101
102 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Bjorn Helgaas2d6054b2016-10-06 13:32:15 -0500103 pp->dbi_base = devm_ioremap_resource(dev, res);
Bjorn Helgaasbb8a7942016-10-06 13:32:15 -0500104 if (IS_ERR(pp->dbi_base))
105 return PTR_ERR(pp->dbi_base);
Joao Pinto5a3aa2a2016-03-10 14:44:52 -0600106
107 ret = dw_plat_add_pcie_port(pp, pdev);
108 if (ret < 0)
109 return ret;
110
Joao Pinto5a3aa2a2016-03-10 14:44:52 -0600111 return 0;
112}
113
114static const struct of_device_id dw_plat_pcie_of_match[] = {
115 { .compatible = "snps,dw-pcie", },
116 {},
117};
Joao Pinto5a3aa2a2016-03-10 14:44:52 -0600118
119static struct platform_driver dw_plat_pcie_driver = {
120 .driver = {
121 .name = "dw-pcie",
122 .of_match_table = dw_plat_pcie_of_match,
123 },
124 .probe = dw_plat_pcie_probe,
125};
Paul Gortmakerca8d3342016-07-02 19:13:23 -0400126builtin_platform_driver(dw_plat_pcie_driver);