Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  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
 27struct dw_plat_pcie {
 28	void __iomem		*mem_base;
 29	struct pcie_port	pp;
 30};
 31
 32static 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
 39static 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
 48static struct pcie_host_ops dw_plat_pcie_host_ops = {
 49	.host_init = dw_plat_pcie_host_init,
 50};
 51
 52static 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
 87static 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
120static const struct of_device_id dw_plat_pcie_of_match[] = {
121	{ .compatible = "snps,dw-pcie", },
122	{},
123};
124MODULE_DEVICE_TABLE(of, dw_plat_pcie_of_match);
125
126static 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
134module_platform_driver(dw_plat_pcie_driver);
135
136MODULE_AUTHOR("Joao Pinto <Joao.Pinto@synopsys.com>");
137MODULE_DESCRIPTION("Synopsys PCIe host controller glue platform driver");
138MODULE_LICENSE("GPL v2");