aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2015-11-03 09:39:32 -0500
committerBjorn Helgaas <bhelgaas@google.com>2015-11-03 09:39:32 -0500
commit7225107e158241b7e22f15b9f4c3db0b3330984d (patch)
tree7050af734ec625ac7ee53b8487b8ece65a5f0967
parent4ed31f24a6416cc60bc8e92c25b2de3060fbedf8 (diff)
parentbd33b87a9a15f8182e8c6a49f5413e7ef79372bf (diff)
Merge branch 'pci/host-layerscape' into next
* pci/host-layerscape: PCI: layerscape: Add ls_pcie_msi_host_init() PCI: layerscape: Add support for LS1043a and LS2080a PCI: layerscape: Remove unused fields from struct ls_pcie PCI: layerscape: Update ls_add_pcie_port() PCI: layerscape: Factor out SCFG related function PCI: layerscape: Ignore PCIe controllers in Endpoint mode PCI: layerscape: Remove ls_pcie_establish_link()
-rw-r--r--Documentation/devicetree/bindings/pci/layerscape-pci.txt14
-rw-r--r--drivers/pci/host/Kconfig2
-rw-r--r--drivers/pci/host/pci-layerscape.c199
3 files changed, 161 insertions, 54 deletions
diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt
index 6286f049bf18..e3767857d30d 100644
--- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt
+++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt
@@ -1,10 +1,20 @@
1Freescale Layerscape PCIe controller 1Freescale Layerscape PCIe controller
2 2
3This PCIe host controller is based on the Synopsis Designware PCIe IP 3This PCIe host controller is based on the Synopsys DesignWare PCIe IP
4and thus inherits all the common properties defined in designware-pcie.txt. 4and thus inherits all the common properties defined in designware-pcie.txt.
5 5
6This controller derives its clocks from the Reset Configuration Word (RCW)
7which is used to describe the PLL settings at the time of chip-reset.
8
9Also as per the available Reference Manuals, there is no specific 'version'
10register available in the Freescale PCIe controller register set,
11which can allow determining the underlying DesignWare PCIe controller version
12information.
13
6Required properties: 14Required properties:
7- compatible: should contain the platform identifier such as "fsl,ls1021a-pcie" 15- compatible: should contain the platform identifier such as:
16 "fsl,ls1021a-pcie", "snps,dw-pcie"
17 "fsl,ls2080a-pcie", "snps,dw-pcie"
8- reg: base addresses and lengths of the PCIe controller 18- reg: base addresses and lengths of the PCIe controller
9- interrupts: A list of interrupt outputs of the controller. Must contain an 19- interrupts: A list of interrupt outputs of the controller. Must contain an
10 entry for each entry in the interrupt-names property. 20 entry for each entry in the interrupt-names property.
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 70370f28da87..f131ba947dc6 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -107,7 +107,7 @@ config PCI_XGENE_MSI
107 107
108config PCI_LAYERSCAPE 108config PCI_LAYERSCAPE
109 bool "Freescale Layerscape PCIe controller" 109 bool "Freescale Layerscape PCIe controller"
110 depends on OF && ARM 110 depends on OF && (ARM || ARCH_LAYERSCAPE)
111 select PCIE_DW 111 select PCIE_DW
112 select MFD_SYSCON 112 select MFD_SYSCON
113 help 113 help
diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c
index b2328ea13dcf..3923bed93c7e 100644
--- a/drivers/pci/host/pci-layerscape.c
+++ b/drivers/pci/host/pci-layerscape.c
@@ -3,7 +3,7 @@
3 * 3 *
4 * Copyright (C) 2014 Freescale Semiconductor. 4 * Copyright (C) 2014 Freescale Semiconductor.
5 * 5 *
6 * Author: Minghuan Lian <Minghuan.Lian@freescale.com> 6 * Author: Minghuan Lian <Minghuan.Lian@freescale.com>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 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 9 * it under the terms of the GNU General Public License version 2 as
@@ -11,7 +11,6 @@
11 */ 11 */
12 12
13#include <linux/kernel.h> 13#include <linux/kernel.h>
14#include <linux/delay.h>
15#include <linux/interrupt.h> 14#include <linux/interrupt.h>
16#include <linux/module.h> 15#include <linux/module.h>
17#include <linux/of_pci.h> 16#include <linux/of_pci.h>
@@ -32,27 +31,60 @@
32#define LTSSM_STATE_MASK 0x3f 31#define LTSSM_STATE_MASK 0x3f
33#define LTSSM_PCIE_L0 0x11 /* L0 state */ 32#define LTSSM_PCIE_L0 0x11 /* L0 state */
34 33
35/* Symbol Timer Register and Filter Mask Register 1 */ 34/* PEX Internal Configuration Registers */
36#define PCIE_STRFMR1 0x71c 35#define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */
36#define PCIE_DBI_RO_WR_EN 0x8bc /* DBI Read-Only Write Enable Register */
37
38/* PEX LUT registers */
39#define PCIE_LUT_DBG 0x7FC /* PEX LUT Debug Register */
40
41struct ls_pcie_drvdata {
42 u32 lut_offset;
43 u32 ltssm_shift;
44 struct pcie_host_ops *ops;
45};
37 46
38struct ls_pcie { 47struct ls_pcie {
39 struct list_head node;
40 struct device *dev;
41 struct pci_bus *bus;
42 void __iomem *dbi; 48 void __iomem *dbi;
49 void __iomem *lut;
43 struct regmap *scfg; 50 struct regmap *scfg;
44 struct pcie_port pp; 51 struct pcie_port pp;
52 const struct ls_pcie_drvdata *drvdata;
45 int index; 53 int index;
46 int msi_irq;
47}; 54};
48 55
49#define to_ls_pcie(x) container_of(x, struct ls_pcie, pp) 56#define to_ls_pcie(x) container_of(x, struct ls_pcie, pp)
50 57
51static int ls_pcie_link_up(struct pcie_port *pp) 58static bool ls_pcie_is_bridge(struct ls_pcie *pcie)
59{
60 u32 header_type;
61
62 header_type = ioread8(pcie->dbi + PCI_HEADER_TYPE);
63 header_type &= 0x7f;
64
65 return header_type == PCI_HEADER_TYPE_BRIDGE;
66}
67
68/* Clear multi-function bit */
69static void ls_pcie_clear_multifunction(struct ls_pcie *pcie)
70{
71 iowrite8(PCI_HEADER_TYPE_BRIDGE, pcie->dbi + PCI_HEADER_TYPE);
72}
73
74/* Fix class value */
75static void ls_pcie_fix_class(struct ls_pcie *pcie)
76{
77 iowrite16(PCI_CLASS_BRIDGE_PCI, pcie->dbi + PCI_CLASS_DEVICE);
78}
79
80static int ls1021_pcie_link_up(struct pcie_port *pp)
52{ 81{
53 u32 state; 82 u32 state;
54 struct ls_pcie *pcie = to_ls_pcie(pp); 83 struct ls_pcie *pcie = to_ls_pcie(pp);
55 84
85 if (!pcie->scfg)
86 return 0;
87
56 regmap_read(pcie->scfg, SCFG_PEXMSCPORTSR(pcie->index), &state); 88 regmap_read(pcie->scfg, SCFG_PEXMSCPORTSR(pcie->index), &state);
57 state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK; 89 state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK;
58 90
@@ -62,27 +94,27 @@ static int ls_pcie_link_up(struct pcie_port *pp)
62 return 1; 94 return 1;
63} 95}
64 96
65static int ls_pcie_establish_link(struct pcie_port *pp) 97static void ls1021_pcie_host_init(struct pcie_port *pp)
66{ 98{
67 unsigned int retries; 99 struct ls_pcie *pcie = to_ls_pcie(pp);
100 u32 val, index[2];
68 101
69 for (retries = 0; retries < 200; retries++) { 102 pcie->scfg = syscon_regmap_lookup_by_phandle(pp->dev->of_node,
70 if (dw_pcie_link_up(pp)) 103 "fsl,pcie-scfg");
71 return 0; 104 if (IS_ERR(pcie->scfg)) {
72 usleep_range(100, 1000); 105 dev_err(pp->dev, "No syscfg phandle specified\n");
106 pcie->scfg = NULL;
107 return;
73 } 108 }
74 109
75 dev_err(pp->dev, "phy link never came up\n"); 110 if (of_property_read_u32_array(pp->dev->of_node,
76 return -EINVAL; 111 "fsl,pcie-scfg", index, 2)) {
77} 112 pcie->scfg = NULL;
78 113 return;
79static void ls_pcie_host_init(struct pcie_port *pp) 114 }
80{ 115 pcie->index = index[1];
81 struct ls_pcie *pcie = to_ls_pcie(pp);
82 u32 val;
83 116
84 dw_pcie_setup_rc(pp); 117 dw_pcie_setup_rc(pp);
85 ls_pcie_establish_link(pp);
86 118
87 /* 119 /*
88 * LS1021A Workaround for internal TKT228622 120 * LS1021A Workaround for internal TKT228622
@@ -93,21 +125,97 @@ static void ls_pcie_host_init(struct pcie_port *pp)
93 iowrite32(val, pcie->dbi + PCIE_STRFMR1); 125 iowrite32(val, pcie->dbi + PCIE_STRFMR1);
94} 126}
95 127
128static int ls_pcie_link_up(struct pcie_port *pp)
129{
130 struct ls_pcie *pcie = to_ls_pcie(pp);
131 u32 state;
132
133 state = (ioread32(pcie->lut + PCIE_LUT_DBG) >>
134 pcie->drvdata->ltssm_shift) &
135 LTSSM_STATE_MASK;
136
137 if (state < LTSSM_PCIE_L0)
138 return 0;
139
140 return 1;
141}
142
143static void ls_pcie_host_init(struct pcie_port *pp)
144{
145 struct ls_pcie *pcie = to_ls_pcie(pp);
146
147 iowrite32(1, pcie->dbi + PCIE_DBI_RO_WR_EN);
148 ls_pcie_fix_class(pcie);
149 ls_pcie_clear_multifunction(pcie);
150 iowrite32(0, pcie->dbi + PCIE_DBI_RO_WR_EN);
151}
152
153static int ls_pcie_msi_host_init(struct pcie_port *pp,
154 struct msi_controller *chip)
155{
156 struct device_node *msi_node;
157 struct device_node *np = pp->dev->of_node;
158
159 /*
160 * The MSI domain is set by the generic of_msi_configure(). This
161 * .msi_host_init() function keeps us from doing the default MSI
162 * domain setup in dw_pcie_host_init() and also enforces the
163 * requirement that "msi-parent" exists.
164 */
165 msi_node = of_parse_phandle(np, "msi-parent", 0);
166 if (!msi_node) {
167 dev_err(pp->dev, "failed to find msi-parent\n");
168 return -EINVAL;
169 }
170
171 return 0;
172}
173
174static struct pcie_host_ops ls1021_pcie_host_ops = {
175 .link_up = ls1021_pcie_link_up,
176 .host_init = ls1021_pcie_host_init,
177 .msi_host_init = ls_pcie_msi_host_init,
178};
179
96static struct pcie_host_ops ls_pcie_host_ops = { 180static struct pcie_host_ops ls_pcie_host_ops = {
97 .link_up = ls_pcie_link_up, 181 .link_up = ls_pcie_link_up,
98 .host_init = ls_pcie_host_init, 182 .host_init = ls_pcie_host_init,
183 .msi_host_init = ls_pcie_msi_host_init,
184};
185
186static struct ls_pcie_drvdata ls1021_drvdata = {
187 .ops = &ls1021_pcie_host_ops,
188};
189
190static struct ls_pcie_drvdata ls1043_drvdata = {
191 .lut_offset = 0x10000,
192 .ltssm_shift = 24,
193 .ops = &ls_pcie_host_ops,
99}; 194};
100 195
101static int ls_add_pcie_port(struct ls_pcie *pcie) 196static struct ls_pcie_drvdata ls2080_drvdata = {
197 .lut_offset = 0x80000,
198 .ltssm_shift = 0,
199 .ops = &ls_pcie_host_ops,
200};
201
202static const struct of_device_id ls_pcie_of_match[] = {
203 { .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata },
204 { .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata },
205 { .compatible = "fsl,ls2080a-pcie", .data = &ls2080_drvdata },
206 { },
207};
208MODULE_DEVICE_TABLE(of, ls_pcie_of_match);
209
210static int __init ls_add_pcie_port(struct pcie_port *pp,
211 struct platform_device *pdev)
102{ 212{
103 struct pcie_port *pp;
104 int ret; 213 int ret;
214 struct ls_pcie *pcie = to_ls_pcie(pp);
105 215
106 pp = &pcie->pp; 216 pp->dev = &pdev->dev;
107 pp->dev = pcie->dev;
108 pp->dbi_base = pcie->dbi; 217 pp->dbi_base = pcie->dbi;
109 pp->root_bus_nr = -1; 218 pp->ops = pcie->drvdata->ops;
110 pp->ops = &ls_pcie_host_ops;
111 219
112 ret = dw_pcie_host_init(pp); 220 ret = dw_pcie_host_init(pp);
113 if (ret) { 221 if (ret) {
@@ -120,17 +228,19 @@ static int ls_add_pcie_port(struct ls_pcie *pcie)
120 228
121static int __init ls_pcie_probe(struct platform_device *pdev) 229static int __init ls_pcie_probe(struct platform_device *pdev)
122{ 230{
231 const struct of_device_id *match;
123 struct ls_pcie *pcie; 232 struct ls_pcie *pcie;
124 struct resource *dbi_base; 233 struct resource *dbi_base;
125 u32 index[2];
126 int ret; 234 int ret;
127 235
236 match = of_match_device(ls_pcie_of_match, &pdev->dev);
237 if (!match)
238 return -ENODEV;
239
128 pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); 240 pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
129 if (!pcie) 241 if (!pcie)
130 return -ENOMEM; 242 return -ENOMEM;
131 243
132 pcie->dev = &pdev->dev;
133
134 dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); 244 dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
135 pcie->dbi = devm_ioremap_resource(&pdev->dev, dbi_base); 245 pcie->dbi = devm_ioremap_resource(&pdev->dev, dbi_base);
136 if (IS_ERR(pcie->dbi)) { 246 if (IS_ERR(pcie->dbi)) {
@@ -138,20 +248,13 @@ static int __init ls_pcie_probe(struct platform_device *pdev)
138 return PTR_ERR(pcie->dbi); 248 return PTR_ERR(pcie->dbi);
139 } 249 }
140 250
141 pcie->scfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, 251 pcie->drvdata = match->data;
142 "fsl,pcie-scfg"); 252 pcie->lut = pcie->dbi + pcie->drvdata->lut_offset;
143 if (IS_ERR(pcie->scfg)) {
144 dev_err(&pdev->dev, "No syscfg phandle specified\n");
145 return PTR_ERR(pcie->scfg);
146 }
147 253
148 ret = of_property_read_u32_array(pdev->dev.of_node, 254 if (!ls_pcie_is_bridge(pcie))
149 "fsl,pcie-scfg", index, 2); 255 return -ENODEV;
150 if (ret)
151 return ret;
152 pcie->index = index[1];
153 256
154 ret = ls_add_pcie_port(pcie); 257 ret = ls_add_pcie_port(&pcie->pp, pdev);
155 if (ret < 0) 258 if (ret < 0)
156 return ret; 259 return ret;
157 260
@@ -160,12 +263,6 @@ static int __init ls_pcie_probe(struct platform_device *pdev)
160 return 0; 263 return 0;
161} 264}
162 265
163static const struct of_device_id ls_pcie_of_match[] = {
164 { .compatible = "fsl,ls1021a-pcie" },
165 { },
166};
167MODULE_DEVICE_TABLE(of, ls_pcie_of_match);
168
169static struct platform_driver ls_pcie_driver = { 266static struct platform_driver ls_pcie_driver = {
170 .driver = { 267 .driver = {
171 .name = "layerscape-pcie", 268 .name = "layerscape-pcie",