aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorMinghuan Lian <Minghuan.Lian@freescale.com>2014-11-05 03:45:11 -0500
committerBjorn Helgaas <bhelgaas@google.com>2014-11-13 11:31:52 -0500
commit62d0ff83c6e2221662fa0dccf2de096bdc7a2fc4 (patch)
treea28f30c8b8bb8585e1ede12217ac18efe2041f61 /drivers/pci
parentf114040e3ea6e07372334ade75d1ee0775c355e1 (diff)
PCI: layerscape: Add Freescale Layerscape PCIe driver
Add support for Freescale Layerscape PCIe controller. This driver re-uses the Synopsis DesignWare core code. [bhelgaas: add Kconfig dependency on CONFIG_ARM] Signed-off-by: Minghuan Lian <Minghuan.Lian@freescale.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/host/Kconfig8
-rw-r--r--drivers/pci/host/Makefile1
-rw-r--r--drivers/pci/host/pci-layerscape.c179
3 files changed, 188 insertions, 0 deletions
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 3dc25fad490c..67e2cc5a0bd4 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -91,4 +91,12 @@ config PCI_XGENE
91 There are 5 internal PCIe ports available. Each port is GEN3 capable 91 There are 5 internal PCIe ports available. Each port is GEN3 capable
92 and have varied lanes from x1 to x8. 92 and have varied lanes from x1 to x8.
93 93
94config PCI_LAYERSCAPE
95 bool "Freescale Layerscape PCIe controller"
96 depends on OF && ARM
97 select PCIE_DW
98 select MFD_SYSCON
99 help
100 Say Y here if you want PCIe controller support on Layerscape SoCs.
101
94endmenu 102endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 26b3461d68d7..44c26998027f 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
11obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o 11obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
12obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o 12obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
13obj-$(CONFIG_PCI_XGENE) += pci-xgene.o 13obj-$(CONFIG_PCI_XGENE) += pci-xgene.o
14obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c
new file mode 100644
index 000000000000..6697b1a4d4fa
--- /dev/null
+++ b/drivers/pci/host/pci-layerscape.c
@@ -0,0 +1,179 @@
1/*
2 * PCIe host controller driver for Freescale Layerscape SoCs
3 *
4 * Copyright (C) 2014 Freescale Semiconductor.
5 *
6 * Author: Minghuan Lian <Minghuan.Lian@freescale.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
13#include <linux/kernel.h>
14#include <linux/delay.h>
15#include <linux/interrupt.h>
16#include <linux/module.h>
17#include <linux/of_pci.h>
18#include <linux/of_platform.h>
19#include <linux/of_irq.h>
20#include <linux/of_address.h>
21#include <linux/pci.h>
22#include <linux/platform_device.h>
23#include <linux/resource.h>
24#include <linux/mfd/syscon.h>
25#include <linux/regmap.h>
26
27#include "pcie-designware.h"
28
29/* PEX1/2 Misc Ports Status Register */
30#define SCFG_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4)
31#define LTSSM_STATE_SHIFT 20
32#define LTSSM_STATE_MASK 0x3f
33#define LTSSM_PCIE_L0 0x11 /* L0 state */
34
35/* Symbol Timer Register and Filter Mask Register 1 */
36#define PCIE_STRFMR1 0x71c
37
38struct ls_pcie {
39 struct list_head node;
40 struct device *dev;
41 struct pci_bus *bus;
42 void __iomem *dbi;
43 struct regmap *scfg;
44 struct pcie_port pp;
45 int index;
46 int msi_irq;
47};
48
49#define to_ls_pcie(x) container_of(x, struct ls_pcie, pp)
50
51static int ls_pcie_link_up(struct pcie_port *pp)
52{
53 u32 state;
54 struct ls_pcie *pcie = to_ls_pcie(pp);
55
56 regmap_read(pcie->scfg, SCFG_PEXMSCPORTSR(pcie->index), &state);
57 state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK;
58
59 if (state < LTSSM_PCIE_L0)
60 return 0;
61
62 return 1;
63}
64
65static void ls_pcie_host_init(struct pcie_port *pp)
66{
67 struct ls_pcie *pcie = to_ls_pcie(pp);
68 int count = 0;
69 u32 val;
70
71 dw_pcie_setup_rc(pp);
72
73 while (!ls_pcie_link_up(pp)) {
74 usleep_range(100, 1000);
75 count++;
76 if (count >= 200) {
77 dev_err(pp->dev, "phy link never came up\n");
78 return;
79 }
80 }
81
82 /*
83 * LS1021A Workaround for internal TKT228622
84 * to fix the INTx hang issue
85 */
86 val = ioread32(pcie->dbi + PCIE_STRFMR1);
87 val &= 0xffff;
88 iowrite32(val, pcie->dbi + PCIE_STRFMR1);
89}
90
91static struct pcie_host_ops ls_pcie_host_ops = {
92 .link_up = ls_pcie_link_up,
93 .host_init = ls_pcie_host_init,
94};
95
96static int ls_add_pcie_port(struct ls_pcie *pcie)
97{
98 struct pcie_port *pp;
99 int ret;
100
101 pp = &pcie->pp;
102 pp->dev = pcie->dev;
103 pp->dbi_base = pcie->dbi;
104 pp->root_bus_nr = -1;
105 pp->ops = &ls_pcie_host_ops;
106
107 ret = dw_pcie_host_init(pp);
108 if (ret) {
109 dev_err(pp->dev, "failed to initialize host\n");
110 return ret;
111 }
112
113 return 0;
114}
115
116static int __init ls_pcie_probe(struct platform_device *pdev)
117{
118 struct ls_pcie *pcie;
119 struct resource *dbi_base;
120 u32 index[2];
121 int ret;
122
123 pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
124 if (!pcie)
125 return -ENOMEM;
126
127 pcie->dev = &pdev->dev;
128
129 dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
130 if (!dbi_base) {
131 dev_err(&pdev->dev, "missing *regs* space\n");
132 return -ENODEV;
133 }
134
135 pcie->dbi = devm_ioremap_resource(&pdev->dev, dbi_base);
136 if (IS_ERR(pcie->dbi))
137 return PTR_ERR(pcie->dbi);
138
139 pcie->scfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
140 "fsl,pcie-scfg");
141 if (IS_ERR(pcie->scfg)) {
142 dev_err(&pdev->dev, "No syscfg phandle specified\n");
143 return PTR_ERR(pcie->scfg);
144 }
145
146 ret = of_property_read_u32_array(pdev->dev.of_node,
147 "fsl,pcie-scfg", index, 2);
148 if (ret)
149 return ret;
150 pcie->index = index[1];
151
152 ret = ls_add_pcie_port(pcie);
153 if (ret < 0)
154 return ret;
155
156 platform_set_drvdata(pdev, pcie);
157
158 return 0;
159}
160
161static const struct of_device_id ls_pcie_of_match[] = {
162 { .compatible = "fsl,ls1021a-pcie" },
163 { },
164};
165MODULE_DEVICE_TABLE(of, ls_pcie_of_match);
166
167static struct platform_driver ls_pcie_driver = {
168 .driver = {
169 .name = "layerscape-pcie",
170 .owner = THIS_MODULE,
171 .of_match_table = ls_pcie_of_match,
172 },
173};
174
175module_platform_driver_probe(ls_pcie_driver, ls_pcie_probe);
176
177MODULE_AUTHOR("Minghuan Lian <Minghuan.Lian@freescale.com>");
178MODULE_DESCRIPTION("Freescale Layerscape PCIe host controller driver");
179MODULE_LICENSE("GPL v2");