/* * PCIe RC driver for Synopsys DesignWare Core * * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) * * Authors: Joao Pinto * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "pcie-designware.h" struct dw_plat_pcie { struct pcie_port pp; /* pp.dbi_base is DT 0th resource */ }; static irqreturn_t dw_plat_pcie_msi_irq_handler(int irq, void *arg) { struct pcie_port *pp = arg; return dw_handle_msi_irq(pp); } static int dw_plat_pcie_host_init(struct pcie_port *pp) { dw_pcie_setup_rc(pp); dw_pcie_wait_for_link(pp); if (IS_ENABLED(CONFIG_PCI_MSI)) dw_pcie_msi_init(pp); return 0; } static struct 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 = pp->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; ret = devm_request_irq(dev, pp->msi_irq, dw_plat_pcie_msi_irq_handler, IRQF_SHARED, "dw-plat-pcie-msi", pp); if (ret) { dev_err(dev, "failed to request MSI IRQ\n"); return ret; } } 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 int dw_plat_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct dw_plat_pcie *dw_plat_pcie; struct pcie_port *pp; 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; pp = &dw_plat_pcie->pp; pp->dev = dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pp->dbi_base = devm_ioremap_resource(dev, res); if (IS_ERR(pp->dbi_base)) return PTR_ERR(pp->dbi_base); ret = dw_plat_add_pcie_port(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, }, .probe = dw_plat_pcie_probe, }; builtin_platform_driver(dw_plat_pcie_driver);