pcie-iproc-platform.c 3.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*
 * Copyright (C) 2015 Broadcom Corporation
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation version 2.
 *
 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
 * kind, whether express or implied; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/phy/phy.h>

#include "pcie-iproc.h"

R
Ray Jui 已提交
29 30 31 32 33 34 35 36 37 38 39 40
static const struct of_device_id iproc_pcie_of_match_table[] = {
	{
		.compatible = "brcm,iproc-pcie",
		.data = (int *)IPROC_PCIE_PAXB,
	}, {
		.compatible = "brcm,iproc-pcie-paxc",
		.data = (int *)IPROC_PCIE_PAXC,
	},
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, iproc_pcie_of_match_table);

41 42
static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
{
R
Ray Jui 已提交
43
	const struct of_device_id *of_id;
44 45 46 47 48 49 50
	struct iproc_pcie *pcie;
	struct device_node *np = pdev->dev.of_node;
	struct resource reg;
	resource_size_t iobase = 0;
	LIST_HEAD(res);
	int ret;

R
Ray Jui 已提交
51 52 53 54
	of_id = of_match_device(iproc_pcie_of_match_table, &pdev->dev);
	if (!of_id)
		return -EINVAL;

55 56 57 58 59
	pcie = devm_kzalloc(&pdev->dev, sizeof(struct iproc_pcie), GFP_KERNEL);
	if (!pcie)
		return -ENOMEM;

	pcie->dev = &pdev->dev;
R
Ray Jui 已提交
60
	pcie->type = (enum iproc_pcie_type)of_id->data;
61 62 63 64 65 66 67 68 69 70 71 72 73
	platform_set_drvdata(pdev, pcie);

	ret = of_address_to_resource(np, 0, &reg);
	if (ret < 0) {
		dev_err(pcie->dev, "unable to obtain controller resources\n");
		return ret;
	}

	pcie->base = devm_ioremap(pcie->dev, reg.start, resource_size(&reg));
	if (!pcie->base) {
		dev_err(pcie->dev, "unable to map controller registers\n");
		return -ENOMEM;
	}
R
Ray Jui 已提交
74
	pcie->base_addr = reg.start;
75

R
Ray Jui 已提交
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
	if (of_property_read_bool(np, "brcm,pcie-ob")) {
		u32 val;

		ret = of_property_read_u32(np, "brcm,pcie-ob-axi-offset",
					   &val);
		if (ret) {
			dev_err(pcie->dev,
				"missing brcm,pcie-ob-axi-offset property\n");
			return ret;
		}
		pcie->ob.axi_offset = val;

		ret = of_property_read_u32(np, "brcm,pcie-ob-window-size",
					   &val);
		if (ret) {
			dev_err(pcie->dev,
				"missing brcm,pcie-ob-window-size property\n");
			return ret;
		}
		pcie->ob.window_size = (resource_size_t)val * SZ_1M;

		if (of_property_read_bool(np, "brcm,pcie-ob-oarr-size"))
			pcie->ob.set_oarr_size = true;

		pcie->need_ob_cfg = true;
	}

103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
	/* PHY use is optional */
	pcie->phy = devm_phy_get(&pdev->dev, "pcie-phy");
	if (IS_ERR(pcie->phy)) {
		if (PTR_ERR(pcie->phy) == -EPROBE_DEFER)
			return -EPROBE_DEFER;
		pcie->phy = NULL;
	}

	ret = of_pci_get_host_bridge_resources(np, 0, 0xff, &res, &iobase);
	if (ret) {
		dev_err(pcie->dev,
			"unable to get PCI host bridge resources\n");
		return ret;
	}

118 119
	pcie->map_irq = of_irq_parse_and_map_pci;

120
	ret = iproc_pcie_setup(pcie, &res);
121
	if (ret)
122 123
		dev_err(pcie->dev, "PCIe controller setup failed\n");

124 125 126
	pci_free_resource_list(&res);

	return ret;
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
}

static int iproc_pcie_pltfm_remove(struct platform_device *pdev)
{
	struct iproc_pcie *pcie = platform_get_drvdata(pdev);

	return iproc_pcie_remove(pcie);
}

static struct platform_driver iproc_pcie_pltfm_driver = {
	.driver = {
		.name = "iproc-pcie",
		.of_match_table = of_match_ptr(iproc_pcie_of_match_table),
	},
	.probe = iproc_pcie_pltfm_probe,
	.remove = iproc_pcie_pltfm_remove,
};
module_platform_driver(iproc_pcie_pltfm_driver);

MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>");
MODULE_DESCRIPTION("Broadcom iPROC PCIe platform driver");
MODULE_LICENSE("GPL v2");