forked from luck/tmp_suning_uos_patched
7c5925afbc
Implement a multiplexed IRQ domain hierarchy API in the pcie-designware host bridge driver that funnels all MSI IRQs into a single parent interrupt, moving away from the obsolete struct msi_controller based API. Although the old implementation API is still available, pcie-designware will now use the multiplexed IRQ domains hierarchical API. Remove all existing dwc based host bridges MSI IRQs handlers, in that the hierarchical API now handles MSI IRQs through the hierarchical/chained MSI domain implementation. Signed-off-by: Gustavo Pimentel <gustavo.pimentel@synopsys.com> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Tested-by: Niklas Cassel <niklas.cassel@axis.com> Tested-by: Shawn Guo <shawn.guo@linaro.org> Acked-by: Jingoo Han <jingoohan1@gmail.com> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
125 lines
2.6 KiB
C
125 lines
2.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* PCIe RC driver for Synopsys DesignWare Core
|
|
*
|
|
* Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
|
|
*
|
|
* Authors: Joao Pinto <Joao.Pinto@synopsys.com>
|
|
*/
|
|
#include <linux/clk.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/init.h>
|
|
#include <linux/of_gpio.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/resource.h>
|
|
#include <linux/signal.h>
|
|
#include <linux/types.h>
|
|
|
|
#include "pcie-designware.h"
|
|
|
|
struct dw_plat_pcie {
|
|
struct dw_pcie *pci;
|
|
};
|
|
|
|
static int dw_plat_pcie_host_init(struct pcie_port *pp)
|
|
{
|
|
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
|
|
|
dw_pcie_setup_rc(pp);
|
|
dw_pcie_wait_for_link(pci);
|
|
|
|
if (IS_ENABLED(CONFIG_PCI_MSI))
|
|
dw_pcie_msi_init(pp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = {
|
|
.host_init = dw_plat_pcie_host_init,
|
|
};
|
|
|
|
static int dw_plat_add_pcie_port(struct pcie_port *pp,
|
|
struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
int ret;
|
|
|
|
pp->irq = platform_get_irq(pdev, 1);
|
|
if (pp->irq < 0)
|
|
return pp->irq;
|
|
|
|
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
|
pp->msi_irq = platform_get_irq(pdev, 0);
|
|
if (pp->msi_irq < 0)
|
|
return pp->msi_irq;
|
|
}
|
|
|
|
pp->root_bus_nr = -1;
|
|
pp->ops = &dw_plat_pcie_host_ops;
|
|
|
|
ret = dw_pcie_host_init(pp);
|
|
if (ret) {
|
|
dev_err(dev, "failed to initialize host\n");
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct dw_pcie_ops dw_pcie_ops = {
|
|
};
|
|
|
|
static int dw_plat_pcie_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct dw_plat_pcie *dw_plat_pcie;
|
|
struct dw_pcie *pci;
|
|
struct resource *res; /* Resource from DT */
|
|
int ret;
|
|
|
|
dw_plat_pcie = devm_kzalloc(dev, sizeof(*dw_plat_pcie), GFP_KERNEL);
|
|
if (!dw_plat_pcie)
|
|
return -ENOMEM;
|
|
|
|
pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
|
|
if (!pci)
|
|
return -ENOMEM;
|
|
|
|
pci->dev = dev;
|
|
pci->ops = &dw_pcie_ops;
|
|
|
|
dw_plat_pcie->pci = pci;
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
pci->dbi_base = devm_ioremap_resource(dev, res);
|
|
if (IS_ERR(pci->dbi_base))
|
|
return PTR_ERR(pci->dbi_base);
|
|
|
|
platform_set_drvdata(pdev, dw_plat_pcie);
|
|
|
|
ret = dw_plat_add_pcie_port(&pci->pp, pdev);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct of_device_id dw_plat_pcie_of_match[] = {
|
|
{ .compatible = "snps,dw-pcie", },
|
|
{},
|
|
};
|
|
|
|
static struct platform_driver dw_plat_pcie_driver = {
|
|
.driver = {
|
|
.name = "dw-pcie",
|
|
.of_match_table = dw_plat_pcie_of_match,
|
|
.suppress_bind_attrs = true,
|
|
},
|
|
.probe = dw_plat_pcie_probe,
|
|
};
|
|
builtin_platform_driver(dw_plat_pcie_driver);
|